Payouts
frameOS supports payouts to cards and bank accounts. Payouts are enabled through the card_receive and bank_account_receive capabilities — each has its own set of requirements that must be satisfied before the capability becomes active and funds can be disbursed.
Both payout types require a verified KYC record on the account. Identity verification is the foundation of payout eligibility — without a verified individual, neither capability can be activated.
Payout types
| Capability | Payout method | Requirements |
|---|---|---|
card_receive | Debit card | KYC verified, payment method type, card number, expiration, CVC |
bank_account_receive | ACH bank transfer | KYC verified, payment method type, routing number, account number, account type |
Requirements
Before a payout capability becomes active, frameOS validates that the account has a verified identity and a payment method with the required fields populated. If any fields are missing, the capability remains in a pending state until all requirements are met.
KYC
Both card_receive and bank_account_receive require KYC to have passed on the account. Requesting either capability automatically includes KYC in the onboarding flow. See the KYC documentation for details on what information is collected.
Payment method type
All payment methods require a method_type to be explicitly set. This tells frameOS which set of field requirements to validate against. Valid values are card and ach.
Card requirements
For card_receive, the payment method must have the following fields present and valid:
| Field | Description |
|---|---|
| Method type | Must be set to card |
| Card number | The full card PAN, tokenized |
| Expiration month | Two-digit expiration month |
| Expiration year | Two-digit expiration year |
| CVC | Card verification code |
Bank account requirements
For bank_account_receive, the payment method must have the following fields present and valid:
| Field | Description |
|---|---|
| Method type | Must be set to ach |
| Routing number | The bank's ABA routing number |
| Account number | The bank account number, tokenized |
| Account type | checking or savings |
We recommend also requesting bank_account_verification alongside bank_account_receive. Bank account verification confirms the account holder owns and controls the bank account before payouts are disbursed, reducing the risk of misdirected payments and fraud. See the bank account verification documentation for details.
Card payouts
Create an individual account with the card_receive capability to enable card payouts. KYC is automatically included. The account holder will add and verify their debit card during the onboarding session.
Parameters
Must be individual.
Include card_receive to enable card payouts. KYC is included automatically.
The account holder's email address.
The account holder's first name.
The account holder's last name.
Object containing number and country_code for the account holder's phone.
curl --request POST \
--url https://api.framepayments.com/v1/accounts \
--header 'Authorization: Bearer API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"type": "individual",
"capabilities": ["card_receive"],
"profile": {
"individual": {
"email": "marcia@example.com",
"name": {
"first_name": "Marcia",
"last_name": "Longo"
},
"phone": {
"number": "3107484186",
"country_code": "1"
}
}
}
}'
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"object": "account",
"type": "individual",
"status": "pending",
"external_id": null,
"capabilities": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567891",
"object": "capability",
"name": "kyc",
"status": "pending",
"disabled_reason": null,
"currently_due": [],
"disabled": null
},
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567892",
"object": "capability",
"name": "card_receive",
"status": "pending",
"disabled_reason": null,
"currently_due": [],
"disabled": null
}
],
"profile": {
"individual": {
"email": "marcia@example.com",
"ssn_last_four": null,
"name": {
"first_name": "Marcia",
"middle_name": null,
"last_name": "Longo",
"suffix": null
},
"phone": {
"number": "3107484186",
"country_code": "1"
},
"birthdate": null,
"address": null
}
},
"terms_of_service": null,
"metadata": {},
"livemode": false,
"created": 1721010605
}
Bank account payouts
Create an individual account with the bank_account_receive capability to enable ACH payouts. KYC is automatically included. The account holder will connect and verify their bank account during the onboarding session.
Parameters
Must be individual.
Include bank_account_receive to enable bank account payouts. KYC is included automatically.
The account holder's email address.
The account holder's first name.
The account holder's last name.
Object containing number and country_code for the account holder's phone.
curl --request POST \
--url https://api.framepayments.com/v1/accounts \
--header 'Authorization: Bearer API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"type": "individual",
"capabilities": ["bank_account_receive"],
"profile": {
"individual": {
"email": "marcia@example.com",
"name": {
"first_name": "Marcia",
"last_name": "Longo"
},
"phone": {
"number": "3107484186",
"country_code": "1"
}
}
}
}'
{
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"object": "account",
"type": "individual",
"status": "pending",
"external_id": null,
"capabilities": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567891",
"object": "capability",
"name": "kyc",
"status": "pending",
"disabled_reason": null,
"currently_due": [],
"disabled": null
},
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567892",
"object": "capability",
"name": "bank_account_receive",
"status": "pending",
"disabled_reason": null,
"currently_due": [],
"disabled": null
}
],
"profile": {
"individual": {
"email": "marcia@example.com",
"ssn_last_four": null,
"name": {
"first_name": "Marcia",
"middle_name": null,
"last_name": "Longo",
"suffix": null
},
"phone": {
"number": "3107484186",
"country_code": "1"
},
"birthdate": null,
"address": null
}
},
"terms_of_service": null,
"metadata": {},
"livemode": false,
"created": 1721010605
}
Complete onboarding
Create an onboarding session after the account is created. frameOS guides the account holder through KYC and payment method setup in a single hosted flow. Once all requirements are met and KYC passes, the payout capability transitions to active.
If you're attaching a payment method to an account programmatically — rather than through the hosted onboarding session — include the account parameter when calling POST /v1/payment_methods. This associates the payment method with the account so it can be used as a payout destination. Note that the parameter name is account, not account_id. See the Payment Methods API reference for details.
curl --request POST \
--url https://api.framepayments.com/v1/onboarding_sessions \
--header 'Authorization: Bearer API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"return_url": "https://example.com/onboarding/complete"
}'
After the session completes, retrieve the account to confirm the capability status has transitioned to active. If any required payment method fields are still missing, the capability will remain pending until they are provided.
Testing this flow? See the ACH test account numbers for values you can use to attach a bank account in sandbox mode. The account_closed, account_not_found, and unauthorized numbers fail at attach time — they prevent the bank from ever becoming payout-eligible, rather than failing an individual payout.
Executing a payout
Once the capability is active and the account's payment method is set up, payouts are triggered with a single POST /v1/transfers request. There is no separate payout endpoint — the transfer is the payout.
Provide the account's destination_payment_method_id and omit source_payment_method_id. frameOS resolves the billable event type (transfer.payout.push_to_card or transfer.payout.ach) automatically from the payment method type.
Card payout
Push funds to a debit card. Requires an account with an active card_receive capability and an attached card payment method.
Required parameters
Amount in cents (e.g. 10000 for $100.00).
ID of the account receiving the payout.
ID of the account's debit card payment method.
curl --request POST \
--url https://api.framepayments.com/v1/transfers \
--header 'Authorization: Bearer API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"amount": 10000,
"account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"destination_payment_method_id": "c4d5e6f7-1234-5678-abcd-9e0a1b2c3d4e",
"description": "Weekly earnings"
}'
{
"id": "e36c1cc2-d9f0-44db-a522-12b0aab990db",
"object": "transfer",
"status": "pending",
"amount": 10000,
"currency": "USD",
"platform_fee": 100,
"frame_fee": 15,
"total_fees": 115,
"gross_amount": 10000,
"net_amount": 9885,
"description": "Weekly earnings",
"failure_reason": null,
"charge_intent": null,
"payout": "pay_f47a2dd3-e0b1-55ec-b633-23c1bbc101ec",
"billing_agreement": "b37da62b-c233-4358-967a-7910656fb94f",
"source_payment_method": null,
"destination_payment_method": {
"id": "c4d5e6f7-1234-5678-abcd-9e0a1b2c3d4e",
"object": "payment_method",
"type": "card",
"status": "active",
"livemode": false,
"created": 1773398080,
"updated": 1773398080
},
"metadata": {},
"livemode": false,
"created": 1773415510,
"account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
Bank account payout
Push funds via ACH to a bank account. Requires an account with an active bank_account_receive capability and an attached ACH payment method.
Required parameters
Amount in cents (e.g. 10000 for $100.00).
ID of the account receiving the payout.
ID of the account's bank account payment method.
curl --request POST \
--url https://api.framepayments.com/v1/transfers \
--header 'Authorization: Bearer API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"amount": 10000,
"account_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"destination_payment_method_id": "2a769159-83b7-4b78-8a07-3e5891a414d2",
"description": "Weekly earnings"
}'
{
"id": "f58b3dd4-f1c2-66fd-c744-34d2ccd212fd",
"object": "transfer",
"status": "pending",
"amount": 10000,
"currency": "USD",
"platform_fee": 50,
"frame_fee": 25,
"total_fees": 75,
"gross_amount": 10000,
"net_amount": 9925,
"description": "Weekly earnings",
"failure_reason": null,
"charge_intent": null,
"payout": "pay_a58c4ee5-g2d3-77ge-d855-45e3dde323ge",
"billing_agreement": "b37da62b-c233-4358-967a-7910656fb94f",
"source_payment_method": null,
"destination_payment_method": {
"id": "2a769159-83b7-4b78-8a07-3e5891a414d2",
"object": "payment_method",
"type": "ach",
"status": "active",
"livemode": false,
"created": 1773398080,
"updated": 1773398080
},
"metadata": {},
"livemode": false,
"created": 1773415510,
"account_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
}
Payout processing
Payout transfers are processed asynchronously. The transfer is created synchronously with status: pending and transitions to processing, then succeeded or failed once the processor responds. Subscribe to the transfer.completed and transfer.failed webhooks to be notified when the payout settles.
For the full Transfers API reference — including all parameters, status transitions, fee modes, and charge flows — see Transfers.