Skip to main content
An account is a financial identity you create and own, separate from your own balance and permissions. It holds a balance per currency, carries its own requirements, and has its own capabilities. You create it, you onboard it, and you can act on its behalf. The seller or contractor behind it does not sign up for Bachs, and does not connect an account they already have. One API call brings the account into existence.

Create an account

POST /v1/accounts · scope connected_accounts:write · full field reference → contact_email is the only required field.
  • country defaults to your platform’s country, and decides which requirements the account is given.
  • entity_type is individual or company. Any other value is rejected with 400.
  • configuration names the personas (merchant, recipient) the account is being created for, each as its own key. Nothing is applied for you, so name at least one persona and request at least one capability under it; don’t create an account without both. Sending "configuration": {} is rejected with 422 VALIDATION_ERROR, since an empty object is never what you mean. Naming a persona with no capabilities under it is not itself a capability request; nest capabilities under it, or leave capabilities out of a persona entirely to request everything that persona allows.
  • Every capability lives inside configuration.<persona>.capabilities, so naming one always names the persona it belongs to in the same request. card_collection belongs to merchant; payouts and transfers belong to recipient. Nesting a capability under the wrong persona fails with 400 capability_configuration_mismatch: it is never silently corrected. In sandbox, whatever is granted is granted active immediately rather than pending_review; see Testing.
  • Send "capabilities": {} under a persona when you want to apply it and request nothing yet, for a platform that creates the account now and collects requirements later.
  • responsibilities.fees.collector decides who takes the Bachs processing fee on this account’s direct charges. bachs (the default) means the fee comes out of the charge, so the account settles net. platform means you absorb it: the fee is debited from your balance and the account settles gross. It is fixed at creation and cannot be changed afterwards, and it is returned on every read of the account. platform has no effect on a destination charge. There the account is the counterparty being paid out of a sale that is yours, so there is no fee of theirs for you to absorb; the setting is read but does not apply, and the charge settles as it otherwise would. Set it for accounts that sell in their own name.
An account can start out recipient-only and be given merchant later: POST /v1/accounts/{account_id} takes the same configuration shape, so naming merchant there applies it the same way naming it at creation would. See Update an account.
Omit responsibilities and the account settles net, which is what most platforms want. Take the fee on only when you mean to pay it:
payouts, transfers and conversions are the recipient capabilities, the ones any account needs just to hold and move money it has received. card_collection and the other payment-method capabilities are merchant capabilities: what gives an account the ability to accept payments in the first place. Name both personas in configuration if the account needs to do both. See Capabilities for what each capability permits and how the two groups relate.
A field this endpoint does not read is not rejected. The request still returns 201, and whatever that field was trying to set silently takes its default instead. Nothing in the response marks a field as ignored, so a stale integration can create accounts successfully while quietly missing the setting it thinks it sent. Check the response body against the field reference rather than assuming a field you sent was understood.
Bachs creates a service user to own the account and sends onboarding correspondence to contact_email. An account cannot create other accounts of its own; that returns 403.
Treat the account id as an opaque string. New accounts are prefixed acct_, and accounts created before that convention are unprefixed. Store what the API returns and send it back unchanged rather than validating its shape.

Act on behalf of an account

Send the account id in X-Account-Id. The request runs as that account.
  • The header works on any API-key endpoint, not only Connect ones.
  • Naming an account you do not own returns 403 — your key authenticates fine, it is just not authorized for that account. A non-existent id and another platform’s id return the same 403, so the header cannot probe which ids are real. See Acting as an account.
  • The account’s own capabilities still apply. A restricted payouts capability blocks the withdrawal whether you call it or the account does.
There is no separate API key per account.

Update an account

POST /v1/accounts/{account_id} · scope connected_accounts:write · full field reference → One write path. Set the account’s contact details, request capabilities, and supply requirement values in a single call. Omitted keys are left alone.
  • display_name and contact_email change what you set at creation.
  • configuration requests capabilities, and cannot withdraw one. See Capabilities. It is the same shape as creation: naming a persona as a key is what applies it, if the account does not already have it, whether or not you nest a capability under its capabilities. conversions above works because recipient is either already applied or gets applied by this same call. Unlike creation, a persona named here with capabilities left out never blanket-requests: it only applies the persona.
  • fields carries requirement values, keyed the way the account’s requirements name them. See Requirements.
  • balance_currencies sets which currencies the account holds. See below.

Currencies the account holds

Holding a currency decides what an account settles in, not what it can charge in. A checkout can be priced in any supported currency, held or not, and converts on the way to the balance. This is true for one-time and recurring (subscription) checkouts alike: a subscription priced in a currency the account does not hold still bills each cycle and settles the proceeds into the account’s settlement currency (USD unless it holds the priced currency). A new account holds only USD, so give it a currency when you want its takings to stay in that currency rather than convert. Not every currency Bachs collects in can be held as a balance. Balance currencies lists the ones that can. Asking for any other is refused with 400, and the error names the set that is accepted.
Send true to add a currency and false to remove one. Omit the field and nothing changes. USD is always held, cannot be removed, and does not appear in the response.
Skip this and a charge priced in that currency still goes through, but it converts and settles to the account’s settlement currency (USD by default) rather than staying in the priced currency. It is the account’s own currencies that matter here, not yours: an account you created holds only USD however many currencies your platform holds. (One current exception: a recurring checkout in an unheld currency is still refused with BASE_CURRENCY_NOT_HELD_BY_ORG until the settle-to-USD path ships for renewals.)
This only applies to an account that takes its own payments. An account that is paid through transfers receives whatever currency you send it, and holds it from that point. A partial fields submission is never rejected for being partial. Everything valid is saved, and whatever is still missing or invalid comes back in the requirements block of the same response, so you can save an account holder’s progress as they fill in a form.

Persons

/v1/accounts/{account_id}/persons · scope connected_accounts:read / connected_accounts:write The people behind an account: its representative, its beneficial owners, its directors. A company account needs its representative and every owner at or above the ownership threshold; an individual account has exactly one person.
Roles are flags, not lists. One person is commonly the representative, an owner and a director at once, so relationship carries all of them on the same person rather than repeating them across separate collections. On edit, keys you omit are left alone; sending a key as null clears it. So {"last_name": "Obi-Nwosu"} renames without touching anything else, and naming one relationship flag does not reset the rest. Requirement keys are anchored to the person: persons.per_3a91c0d7.id_document names exactly who needs to re-upload. Removing a person removes the requirements that were only about them.
The representative cannot be removed, because nothing would ask for a replacement and the account would stall. Make another person the representative first.
The response reports whether an ID number is held (id_number_provided) rather than echoing it, and never carries how the person was verified.

Read an account

GET /v1/accounts/{account_id} · scope connected_accounts:read · full field reference → Returns the account with its capabilities, configuration, responsibilities, and requirements blocks. configuration is keyed by persona (merchant, recipient) and, on a single-account read, reads as {} when none apply rather than null. List items do not carry it and return null, the same way they do for capabilities and requirements. responsibilities reads as { "fees": { "collector": "bachs" } } unless the platform took the fee on at creation. GET /v1/accounts lists your accounts. Fields with a standing rejection are listed in requirements.errors, each with the field key and a reason written for the account holder. Like the rest of requirements, they are only on a single-account read, so an index screen built from GET /v1/accounts cannot flag accounts needing attention; read the account to know. Nothing outstanding in requirements does not mean a capability is active. Gate features on the capability’s status. See Capabilities.

include

requirements.values is not returned by default, since it needs a further resource load. Ask for it when you want to read back what has already been submitted:
It adds requirements.values and requirements.persons. Sensitive fields are listed as provided and never echoed back. Comma-separated or repeated (?include=a,b and ?include=a&include=b are the same). An unknown value returns 400 invalid_include rather than being ignored, so a typo does not leave you waiting for a block that never arrives. Anything not asked for is absent from the response rather than null, since null could not be told apart from genuinely empty.

Errors

Account endpoints return the standard error envelope. Common cases:
  • FORBIDDEN (403), your connect capability is not active. See Become a platform.
  • NOT_FOUND (404), the account id is not one of your accounts.
  • VALIDATION_ERROR (422), a field failed validation; inspect errors[].
  • invalid_configuration (400), configuration names a persona that does not exist. Valid keys are merchant and recipient.