Skip to content
Loading keys…

Subaccounts

Create and manage merchant subaccounts for marketplaces and platforms.

Subaccounts let a platform connect merchants and act on their behalf, as part of Sync. A payment made through a connection belongs to the merchant; the platform's commission, set by the connection's pricing, is credited to the platform, or owed to it when the merchant collects on their own providers (Split payments).

private key required

Creating and managing subaccounts requires the private key (sk...).

Endpoints

MethodPathDescription
POST/accountsCreate
GET/accounts/{id}Retrieve
GET/accountsList
PUT/accounts/{id}Update
DELETE/accounts/{id}Delete
POST/accounts/{id}/tokenRegenerate the OAuth authorization token
POST/accounts/{id}/payoutsPay a Lite merchant now (live only)
GET/accounts/{id}/commission-receivablesWhat merchants collecting on their own contracts owe you

The Account (subaccount) object

idstringoptional
Unique identifier.
referencestring?optional
Your own reference for this sub-account. Unique among your connections of the environment for good: a cancelled connection keeps its reference, so it cannot be used again. It cannot be changed after creation.
sandboxbooleanoptional
true for a test-mode sub-account.
capabilitiesstring[]optional
Enabled capabilities for this sub-account (e.g. payment collection).
profileobjectoptional
Profile data about the merchant, filled by the Dashboard during onboarding. The only part you can set is profile.email, the merchant address you give with email on POST or PUT /accounts, where the invitation reminder is sent.
metadataobjectoptional
Your own key-value data, as sent with metadata on POST /accounts. PUT /accounts/{id} merges what you send into it, and a key sent as null is removed. {} when there is none.
callbackstring?optional
URL the merchant is redirected to once connected. HTTPS only: http://localhost and http://127.0.0.1 are accepted with a sandbox key, anything else answers 422. It also registers the origin: a redirect_uri on the authorization link is only honoured when it shares that origin, and refused otherwise. Without a callback, no redirect_uri is accepted.
account_typeenumoptional
The connection mode: direct (the merchant runs a full Wajub account), lite (a hosted portal, always collecting through Wajub) or relay (no merchant account: you collect and Wajub relays the payouts). Defaults to direct, and cannot be changed afterwards.
commission_refund_policyenumoptional
What happens to your commission when a sale is refunded: prorata (default, in proportion to the refund), full (all of it, on the first refund) or none. Settable at creation, and editable only while the connection is pending.
statusenumoptional
pending, active, expired or cancelled: see [the lifecycle](/sync/onboarding#the-lifecycle). GET /accounts?status= filters on this same value.
payment_statusenumoptional
active, inactive (the merchant's verification is still under review) or suspended (by you, or by Wajub when the verification was rejected): whether calls that move money run.
payout_scheduleenumoptional
lite accounts only: manual, daily, weekly or monthly, how often Wajub pays the merchant.
payout_min_amountnumber?optional
lite accounts only: nothing is paid out below this, in the merchant's currency. null means the default, 1 000.
last_payout_atdatetime?optional
lite accounts only: when the merchant was last paid.
pending_changesobject[]optional
Capabilities or pricing you proposed on an accepted connection that the merchant has not answered yet: { id, type, proposed, current, requested_at }.
authorization_urlstring?optional
The onboarding link the merchant follows. Returned only by the two calls that mint it, creating the subaccount and regenerating its token, and never by a later read. Keep it when you get it, or issue a fresh one. A relay connection has none: it is always null there, and regenerating it answers 422.
masterobject?optional
The platform, when loaded: { name }.
connected_merchantobject?optional
The connected merchant, when loaded: { name, email }.
pricingobject?optional
Fee configuration, when loaded: { percentage_fee, fixed_fee, min_fee, max_fee, currency }.
expires_atdatetime?optional
ISO 8601 date the invitation stops being usable, 30 days after its link was last minted. null once a merchant has accepted, since an accepted subaccount never expires, and always null on a relay connection, which has no invitation.
created_atdatetimeoptional
ISO 8601 creation timestamp.
updated_atdatetimeoptional
ISO 8601 timestamp of the last change.

Creating a subaccount

The pricing object accepts percentage_fee, fixed_fee, max_fee, min_fee (all optional, numeric), and currency (required if any fixed/min/max fee is set). email is the merchant's address: Wajub sends the invitation reminder there three days before the invitation expires. It is kept in profile.email, and PUT /accounts/{id} changes it. metadata is yours, returned on the object. A reference already used by one of your connections of the environment, cancelled ones included, answers 422. Past 50 open invitations, the call answers 429 (the cap):

Create a subaccount
curl https://api.wajub.com/accounts \
  -H "Authorization: sk.xxxxxxxxxxxxxxxx…" \
  -H "Content-Type: application/json" \
  -d '{
    "reference": "vendor-482",
    "capabilities": ["payments"],
    "email": "contact@vendor-482.example",
    "pricing": { "percentage_fee": 10, "currency": "XAF" }
  }'

Acting on behalf of a subaccount - the X-Sync header

Once a subaccount is active, the platform can act as it by sending its id in the X-Sync header alongside the platform's own API key. When present and valid, the request runs against the subaccount instead of the platform, resources are created under the subaccount, and its own pricing is applied automatically.

What the platform reaches is what this connection brought: its payments and their refunds and disputes, the customers who bought through it or that it created or named by email or phone (without the merchant's notes, block reason and metadata, and never deleted through it), the links, invoices and beneficiaries it created, the payouts it sent and the events about all of these. The merchant's own sales, links, invoices and payees, and what other platforms brought, are out of scope whatever capabilities were granted, and answer 404. Account types details each resource.

X-Syncheaderoptional
The subaccount's id (e.g. acc_7Yh2Mp), not its reference. Sent alongside the platform's Authorization key.
Create a payment on behalf of a subaccount
curl https://api.wajub.com/payments \
  -H "Authorization: sk.xxxxxxxxxxxxxxxx…" \
  -H "X-Sync: acc_7Yh2Mp" \
  -d '{ "amount": 10000, "currency": "XAF", "email": "client@example.com" }'

On a live connection, PUT /accounts/{id} does not change capabilities or pricing outright: it answers 202 Accepted with the proposal in pending_changes, and the merchant accepts or declines it in their own dashboard. payment_status and callback still apply immediately.

Every resource states the capability it takes, and a resource that states none cannot be reached with X-Sync at all. That is the case for /accounts/*, which you always manage with your own key, and for what belongs to the merchant's whole account rather than to a connection: the balance, webhook endpoints, Shield, Tax and wajub listen.

If the request touchesRequired capability
/payments, /linkspayments
/invoicesinvoices
/customers, /customers/{id}/tax_idscustomers
/refundsrefunds
GET /payments/{id}/refunds, POST /payments/{id}/close with outcome: refundpayments and refunds
/disputesdisputes
/transfers, /beneficiaries, /identitywithdrawals
/, /providers, /eventsread
/channels, /countries, /currenciesnone, catalogues
/balance, /webhooks, /shield, /taxnot available with X-Sync
/accountsnot available with X-Sync

What did you think of this content?