name: bc-payments-manage-academy-payment-methods description: Use when academy staff need to set main currency and create, list, update, or deprecate checkout payment methods; do NOT use for Stripe credential setup when is_credit_card is true (use bc-payments-configure-academy-stripe first), student card save, or subscription cancel/refund. requires: []
Skill: Manage Academy Payment Methods
When to Use
- Use when staff must set the academy's
main_currencyor manage checkout payment method catalog entries (credit card, bank transfer, manual, etc.). - Use Path A when adding a credit card option (
is_credit_card: true) — requires Stripe connected first. - Use Path B for bank transfer, manual, or other non-card methods.
- Do NOT use for Stripe API keys or webhooks — use
bc-payments-configure-academy-stripebefore Path A. - Do NOT use for saving a student's card on file (
POST /v2/payments/card) or cancel/refund flows.
Concepts
- Payment method catalog = checkout option shown to customers (
title,visibility, country filters). It is not a stored card. main_currencyon the academy must be set before payment methods and before many billing flows. Set via admissionsPUT /v1/admissions/academy/me; list valid codes via publicGET /v1/payments/currency.- Credit card setup order: (1)
main_currency, (2) Stripe viabc-payments-configure-academy-stripe, (3) catalog entry withis_credit_card: trueandcurrencymatchingmain_currency. - Academy-owned vs global: staff can CRUD only methods owned by their academy (
academyset). Global methods (academy=null) are visible on GET but cannot be updated or deleted by academy staff. is_cryptois not writable via the payment method API — crypto catalog entries are outside this skill's create/update body.- Capabilities:
read_paymentmethod(list/get),crud_paymentmethod(create/update/delete).Academyheader required on all/academy/routes. - Staff manual deposits require a non-card, non-crypto payment method.
Workflow
Step 0: Set academy main currency (both paths — run first)
- Call
GET /v1/admissions/academy/mewithAuthorization,Academy: <academy_id>, capabilityread_my_academy. Readmain_currency({"code": "USD", "name": "US Dollar"}ornull). - If
main_currencyis null, callGET /v1/payments/currency(public, paginated) and pick a code (e.g.USD,EUR,PEN). - Set it:
PUT /v1/admissions/academy/mewith{"main_currency": "USD"}(code or numeric id), capabilitycrud_my_academy. Confirm with anotherGET /v1/admissions/academy/me. - Use that currency code on new
PaymentMethodrows in Path A or B.
Path A: Credit card (Stripe required — after Step 0)
- Connect Stripe. Load
bc-payments-configure-academy-stripeand complete all its steps. Do not continue untilGET /v1/payments/academy/publishable-key?academy=<id>returns200with a non-emptystripe_publishable_key. - List existing methods:
GET /v1/payments/academy/paymentmethod. If a non-deprecated credit-card method exists,PUTto update it instead of creating a duplicate. - Create catalog entry:
POST /v1/payments/academy/paymentmethodwithis_credit_card: true,is_backed: true,visibility: PUBLIC,currencymatching academymain_currency, and appropriatelang/included_country_codes. Save returnedid. - Verify public checkout:
GET /v1/payments/methods?academy_id=<id>&country_code=<cc>includes the new method.
Path B: Bank transfer / manual / non-card (Step 0 only — no Stripe)
- List methods:
GET /v1/payments/academy/paymentmethod(paginated; optional filtersvisibility,currency_code,lang,deprecated). - Create method:
POST /v1/payments/academy/paymentmethodwithis_credit_card: false,currencymatchingmain_currency(or intentional regional currency), detaileddescription, optionalincluded_country_codes. Save returnedid. - Verify public checkout:
GET /v1/payments/methods?academy_id=<id>&country_code=<cc>(no auth, paginated).
Shared maintenance (both paths)
- Update:
PUT /v1/payments/academy/paymentmethod/<paymentmethod_id>(partial OK; academy-owned only). - Retire: prefer
PUTwithdeprecated: trueandvisibility: HIDDENoverDELETE.
Endpoints
Read academy (main currency)
- Method / path:
GET /v1/admissions/academy/me - Headers:
Authorization,Academy: <academy_id>, optionalAccept-Language: en|es - Permissions:
read_my_academy - Pagination: N/A (single academy object)
Response 200 (subset):
{
"id": 55,
"slug": "miami",
"name": "Miami Academy",
"main_currency": {
"code": "USD",
"name": "US Dollar"
}
}
main_currency may be null if Step 0 is still required.
Set academy main currency
- Method / path:
PUT /v1/admissions/academy/me - Headers:
Authorization,Academy: <academy_id>, optionalAccept-Language: en|es - Permissions:
crud_my_academy - Pagination: N/A
Request:
{
"main_currency": "USD"
}
Response 200: full academy object (same shape as GET); main_currency reflects the saved currency.
List currencies (public)
- Method / path:
GET /v1/payments/currency - Headers: none required
- Pagination: yes —
limit,offset(and optionalcode,namefilters)
Response 200 (subset):
[
{
"code": "USD",
"name": "US Dollar",
"countries": []
},
{
"code": "EUR",
"name": "Euro",
"countries": []
}
]
List payment methods (staff)
- Method / path:
GET /v1/payments/academy/paymentmethod - Headers:
Authorization,Academy: <academy_id>, optionalAccept-Language: en|es - Permissions:
read_paymentmethod - Pagination: yes —
limit,offset; optional queryvisibility,currency_code,lang,deprecated - Scope: returns academy-owned methods and global methods (
academy=null)
Response 200 (subset):
[
{
"id": 1,
"title": "Credit Card",
"description": "Pay securely with Visa, Mastercard, or American Express",
"is_backed": true,
"lang": "en-US",
"is_credit_card": true,
"is_crypto": false,
"third_party_link": null,
"academy": {
"id": 55,
"name": "Miami Academy",
"slug": "miami"
},
"currency": {
"code": "USD",
"name": "US Dollar"
},
"included_country_codes": "US,CA,MX",
"visibility": "PUBLIC",
"deprecated": false
}
]
Get single payment method (staff)
- Method / path:
GET /v1/payments/academy/paymentmethod/<paymentmethod_id> - Headers:
Authorization,Academy: <academy_id> - Permissions:
read_paymentmethod - Pagination: N/A
Response 200: same object shape as one list item above.
Create payment method (staff)
- Method / path:
POST /v1/payments/academy/paymentmethod - Headers:
Authorization,Academy: <academy_id>, optionalAccept-Language: en|es - Permissions:
crud_paymentmethod - Note:
academyis set from theAcademyheader automatically
Request — credit card (Path A):
{
"title": "Credit Card",
"description": "Pay securely with Visa, Mastercard, American Express, or Discover",
"is_backed": true,
"is_credit_card": true,
"currency": "USD",
"lang": "en-US",
"included_country_codes": "US,CA,MX,BR",
"visibility": "PUBLIC",
"deprecated": false
}
Request — bank transfer (Path B):
{
"title": "Bank Transfer - BCP",
"description": "Wire transfer to Banco de Crédito del Perú. Account: 193-123456789-0-00. CCI: 002-193-123456789000-00",
"is_backed": true,
"is_credit_card": false,
"currency": "PEN",
"lang": "es-PE",
"included_country_codes": "PE",
"visibility": "PUBLIC",
"deprecated": false
}
Response 201:
{
"id": 123,
"title": "Bank Transfer - BCP",
"description": "Wire transfer to Banco de Crédito del Perú. Account: 193-123456789-0-00. CCI: 002-193-123456789000-00",
"is_backed": true,
"lang": "es-PE",
"is_credit_card": false,
"currency": "PEN",
"academy": 55,
"included_country_codes": "PE",
"visibility": "PUBLIC",
"deprecated": false
}
Required on create: title, description, lang.
Update payment method (staff)
- Method / path:
PUT /v1/payments/academy/paymentmethod/<paymentmethod_id> - Headers:
Authorization,Academy: <academy_id> - Permissions:
crud_paymentmethod - Restriction: only academy-owned methods; global methods return 404
Request (deprecate example):
{
"deprecated": true,
"visibility": "HIDDEN"
}
Response 200: updated payment method object (create response shape).
Delete payment method (staff)
- Method / path:
DELETE /v1/payments/academy/paymentmethod/<paymentmethod_id> - Headers:
Authorization,Academy: <academy_id> - Permissions:
crud_paymentmethod - Response:
204 No Content
List payment methods (public checkout)
- Method / path:
GET /v1/payments/methods?academy_id=<academy_id>&country_code=<cc> - Headers: none required
- Pagination: yes —
limit,offset; optionalcurrency_code,lang,visibility - Purpose: checkout UI for unauthenticated or student users
Response 200: same item shape as staff list (subset of fields).
Edge Cases
main_currencynull: complete Step 0 before creating payment methods; staff deposit flows may returncurrency-not-foundif neither payment method nor academy has currency.- Invalid currency on academy PUT:
400slugcurrency-not-found— pick a code fromGET /v1/payments/currency. - Credit card without Stripe:
GET /v1/payments/academy/publishable-keyreturns404— loadbc-payments-configure-academy-stripebeforePOSTwithis_credit_card: true. - Skip Stripe for credit card: do not create the catalog entry; charges and checkout will fail without academy Stripe keys.
- Update/delete global method:
404payment-method-not-found— only academy-owned rows are mutable. - Empty public list after create: check
visibility,deprecated,included_country_codes, andcountry_code/currency_codefilters onGET /v1/payments/methods. is_crypto: not accepted on create/update via this API.
Checklist
main_currencyset and confirmed on academy (Step 0).- Path A only: publishable-key GET passed before credit-card
POST. - Payment method created with expected
is_credit_cardflag and matchingcurrency. - Method appears on staff list and on public
GET /v1/payments/methodswith appropriate filters. - If retiring a method,
deprecated+HIDDENapplied (or delete if appropriate).
Next steps
Payment setup is the billing rail layer. To sell at checkout, staff still need catalog layers. Recommend this skill order — do not skip ahead (plans depend on services; courses depend on plans):
- Services — load
bc-payments-manage-serviceswhen available. Defines what the academy sells; must exist before plans. - Plans — load
bc-payments-manage-planswhen available. Bundles services into sellable packages priced inmain_currency. - Courses — load
bc-marketing-create-or-clone-course. Marketing catalog linked to the plan from step 2.
If a follow-on skill is not published yet, tell staff which skill name to use when it exists and stop — do not improvise endpoint-level instructions in this skill.
Closing message for staff: "Payment setup is complete. Next steps: manage academy services, then plans, then create a marketing course — load the skills above in that order."