Pay out to an account

This guide covers paying out to an Account — pushing money out to the account holder's debit card or bank account. Frame models payouts as transfers with a destination payment method and no source. Same primitive as charges, opposite direction.

The work is mostly upstream: the recipient account has to be onboarded with the right capability before any payout can succeed. Once they're onboarded, the payout call itself is a single API request.

Prerequisites

RequirementDetails
Recipient accountAn individual Account that has completed KYC (kyc capability active).
Payout capabilityEither card_receive (push-to-card) or bank_account_receive (ACH credit), with status active.
Destination payment methodA debit card or bank account attached to the recipient. The payment method is what *_receive capabilities verify against.
Active billing agreementYour platform must have an active billing agreement covering the payout category. New merchants get this provisioned by default.

If the recipient hasn't been onboarded yet, start with Run onboarding — request kyc plus the payout capability you need, redirect through an onboarding session, and verify the capability statuses came back active before continuing here.

1. Confirm the recipient account is ready

Retrieve the account and check the payout-relevant capabilities.

You want both:

  • kyc capability active — Frame won't push funds to an unverified individual.
  • card_receive (or bank_account_receive) capability active — the payment method is attached and verified.

If either is pending, route the account holder back through onboarding before attempting a payout. disabled is different — it means the capability was deliberately switched off, by you or by Frame, and onboarding won't lift it.

REQUEST
curl --request GET \
  --url https://api.framepayments.com/v1/accounts/99c6b0da-... \
  --header "Authorization: Bearer $FRAME_SECRET_KEY"
WHAT TO LOOK FOR
{
  "capabilities": [
    { "name": "kyc",          "status": "active" },
    { "name": "card_receive", "status": "active" }
  ]
}

2. Resolve the destination payment method

Each capability is bound to the payment method that verified it. For a payout you need the payment_method_id of the card or bank account that Frame pushes funds to.

List the payment methods on the recipient account and find the one whose type matches the capability you're paying through:

  • card_receive → payment method of type card (typically a debit card).
  • bank_account_receive → payment method of type bank_account.

If the recipient has multiple eligible payment methods, your application chooses which one — Frame doesn't pick a default.

REQUEST
curl --request GET \
  --url 'https://api.framepayments.com/v1/accounts/99c6b0da-.../payment_methods' \
  --header "Authorization: Bearer $FRAME_SECRET_KEY"

3. Create the payout transfer

A payout is a transfer with destination_payment_method_id set and no source_payment_method_id. Frame interprets that shape as a push to the destination. See the transfers concept for the full flow-selection logic.

Pass the destination payment method and the amount in the smallest currency unit (cents for USD). Include account_id to attribute the payout to the recipient — this is what surfaces in reconciliation and webhooks downstream.

speed applies only to ACH destinations: standard (the default, T+4 business days) or same_day (settles the same business day, if you make the submission-window cutoff). same_day is gated per merchant — the request returns a validation error unless same-day ACH is enabled for your account. Omit the field for card_receive destinations; push-to-card has one rail, and the card network sets the timing.

reference is your idempotency key for the payout instruction — your own identifier, unique per environment, up to 255 characters. Re-sending a create with the same reference returns the original transfer and its current status instead of paying out a second time. Omit it and there is no deduplication guarantee.

description and metadata are for your own bookkeeping. They appear on the transfer and on any webhook payload that references it.

REQUEST — push-to-card payout (card_receive destination)
curl --request POST \
  --url https://api.framepayments.com/v1/transfers \
  --header "Authorization: Bearer $FRAME_SECRET_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
  "amount": 50000,
  "currency": "usd",
  "account_id": "99c6b0da-...",
  "destination_payment_method_id": "pm_a1b2c3d4-...",
  "reference": "payout-2026-05-creator-991",
  "description": "May creator payout",
  "metadata": {
    "payout_period": "2026-05"
  }
}'
REQUEST — ACH payout (bank_account_receive destination)
curl --request POST \
  --url https://api.framepayments.com/v1/transfers \
  --header "Authorization: Bearer $FRAME_SECRET_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
  "amount": 50000,
  "currency": "usd",
  "account_id": "99c6b0da-...",
  "destination_payment_method_id": "pm_a1b2c3d4-...",
  "speed": "standard",
  "reference": "payout-2026-05-creator-991",
  "description": "May creator payout",
  "metadata": {
    "payout_period": "2026-05"
  }
}'

4. Handle the response

The transfer is returned synchronously, but for payouts the settlement is asynchronous. The processor confirms the push over the network, not in-line with your API call. Expect the response to come back pending.

Three states to wire for:

  • pending — the initial state. Frame has accepted the payout; the processor hasn't confirmed yet.
  • succeeded — funds have moved. The recipient sees them when their bank or card issuer posts.
  • failed — the processor rejected. failure_reason describes why (typically invalid destination or recipient-side issues).

Don't act on pending as success. Wait for the webhook, or poll GET/v1/transfers/{id} with backoff.

WEBHOOK — transfer.succeeded
{
  "type": "transfer.succeeded",
  "data": {
    "id": "tr_...",
    "status": "succeeded",
    "amount": 50000,
    "currency": "usd",
    "account_id": "99c6b0da-...",
    "destination_payment_method_id": "pm_a1b2c3d4-...",
    "updated": 1748966400
  }
}

5. Reconcile payouts over a period

GET/v1/transfers is the reconciliation surface for payouts. Filter by type=payout and a created time range to pull every payout in a period with its current status.

Webhooks are the primary signal, but a delivery can be missed — an endpoint outage, a dropped retry. The list surface is the recovery path: pull the period's payouts and compare statuses against your own ledger.

Each row carries Frame's canonical payout id (payout) and echoes your reference, so you can join the results back to the payout instructions you issued.

The created filter takes Unix seconds and supports gte, lte, gt, and lt bounds.

REQUEST
curl --get \
  --url https://api.framepayments.com/v1/transfers \
  --header "Authorization: Bearer $FRAME_SECRET_KEY" \
  --data-urlencode 'type=payout' \
  --data-urlencode 'created[gte]=1754006400' \
  --data-urlencode 'created[lte]=1756684800' \
  --data-urlencode 'per_page=100'

Common variations

Account-to-account transfers. A payout pushes funds out with no source. To charge a source payment method and settle the funds to another account in a single call, provide both source_payment_method_id and destination_payment_method_id — the account-to-account flow. The source is charged and the funds are routed to the account that owns the destination payment method, not to your merchant balance. See Accept a payment for the charge-side mechanics and the transfers concept for how field shape selects the flow.

ACH speed tiers. When paying out to a bank_account_receive destination, the optional speed parameter selects the settlement window: standard (the default, T+4 business days) or same_day (same business day, subject to the submission-window cutoff). same_day sits behind a per-merchant feature flag — see the transfers concept for the enablement gotcha. Push-to-card (card_receive) ignores speed — it has one rail, and the issuing bank decides when funds actually post (usually minutes).

Payouts to businesses. Business accounts can receive payouts to a bank_account_receive capability bound to the business's bank account. bank_account_receive on a business account is gated on KYB the way it's gated on KYC for an individual - the entity has to verify, and so does every listed owner and controller. The payout call itself is the same.

Paying out to many recipients at once. If you're paying out to a long list of creators or sellers, create one transfer per recipient. Each transfer is independently settled; there is no bulk-payout primitive in V1.

Gotchas

Symptom: the payout call returns failed immediately with failure_reason: "destination_payment_method_invalid". Why: the destination payment method either doesn't belong to the account you specified, or it's a credit card (which doesn't support push-to-card). Fix: re-list the account's payment methods and confirm you're using a debit card or bank account, and that the account_id matches the payment method's owner.

Symptom: you retried a failed payout and got the same failed transfer back instead of a new attempt. Why: reference is exactly-once, not retry-until-success — re-sending the same reference replays the original transfer at its current status, whatever that status is. Fix: retry a failed or returned payout with a new reference; reuse a reference only to safely recover from timeouts and double-submits.

Symptom: the transfer succeeded according to Frame but the recipient says nothing arrived. Why: the bank's posting delay, especially over weekends or for certain ACH timing windows. Fix: check updated on the transfer — that's when Frame last touched the record, which for a succeeded transfer is when the processor confirmed. Funds usually post within hours for push-to-card, T+4 business days for standard ACH.

Next steps

  • For the conceptual model behind charges, payouts, and transfers, see Transfers concept.
Frame Assistant

Ask anything about Frame's APIs and products