Transfers
A transfer is any movement of funds on Frame. Charging a card, paying out to a bank account, settling between accounts on your platform — all of those are transfers. One primitive, two flows.
How it works
Frame models every money movement as a Transfer. The shape of a transfer — what gets charged, where the funds land — is determined by which payment methods you attach to it:
- Provide a source payment method (card or ACH) and Frame pulls funds from it. This is the charge flow — the everyday "accept a payment" case.
- Provide only a destination payment method (bank account or debit card) and Frame pushes funds to it. This is the payout flow — disbursing to your sellers, contractors, or end users.
- Provide both, and you've described an account-to-account flow on your platform: the source is charged, and the funds settle to the account that owns the destination payment method — not to your merchant balance.
Provide neither and the API returns a validation error — there's no flow to infer.
For a payout to a bank account, speed controls how the ACH transfer settles: standard (default) or same_day. speed has no effect on payouts to a card — those always settle on the card network's own timeline. same_day is gated behind a feature flag and must be enabled for your account before you can use it — see the gotcha below.
Transfers are created synchronously: the API call returns a transfer object with a status the moment it lands. For charge flows the processor responds in-line, so most transfers reach a terminal status by the time you read the response. Payout flows settle asynchronously — the processor needs to confirm — so payouts start in pending and transition once the network responds. Either way, the Transfer is the durable record of the intent and the outcome.
Lifecycle
Which state machine a transfer walks depends on the flow. Every state change emits a transfer.<status> webhook event, and transfer.created fires on every create — wire your integration to events rather than inferring state from the create response.
Payout flow
Payout-backed transfers have a four-state machine:
pending → processing → succeeded | failed
pending— the create response. Frame has accepted the payout; the processor hasn't confirmed yet.processing— the processor has picked up the instruction and is settling it.succeeded— funds have moved. Terminal.failed— the processor declined or the push couldn't be completed. Seefailure_reasonfor the cause. Terminal.
That's the whole machine — payouts never enter the setup or fraud-review states below.
Charge flow
Charge-backed transfers mirror the underlying charge intent and can pass through a much larger machine:
- Setup states —
incomplete,requires_account_or_customer,requires_payment_method,requires_confirmation(a transfer created withconfirm: falsewaits here for a confirm call), andrequires_3d_secure(waiting on a 3DS challenge). - Processing states —
pendingandprocessingwhile the processor responds, andrequires_capturefor authorize-then-capture flows. Most card charges pass through these in-line and reach a terminal status by the time you read the create response. - Fraud review — Sonar can hold a charge in
fraud_reviewuntil you approve it (moves tosucceeded, capturing the held authorization) or decline it (moves tofraud_declined, voiding it). - Terminal states —
succeeded,failed,expired,canceled,fraud_declined. - Post-success states —
reversed(a processor-side reversal during settlement; rare),refunded, anddisputed.
Status transitions are one-way for terminal states (succeeded, failed, expired, canceled, fraud_declined). A succeeded transfer can move to reversed if the processor reverses it during settlement, or to refunded if it's fully refunded — but in practice merchant-facing refund tracking happens on separate Refund records, not parent transfer state; likewise chargebacks are tracked on Dispute records.
Relationships
A transfer is the verb; the rest of the platform supplies the nouns it acts on.
PaymentMethod is the source or destination of funds. A charge transfer reads from one; a payout transfer writes to one; an account-to-account transfer touches both.
Account owns the transfer on the platform side. Every transfer is attributed to an account so you can reconcile activity per seller, per merchant, per end user.
Refunds are separate records linked to the original transfer — they don't transition the parent's status by default. See refunds for the lifecycle on that side.
Gotchas
Symptom: you create a payout transfer and the response says pending — did it work? Why: payouts are asynchronous; the processor confirms over the network, not in-line with your API call. Fix: listen for the transfer.succeeded or transfer.failed webhook rather than inferring from the create response.
Symptom: the amount you charged the customer doesn't match the amount your seller received. Why: the billing agreement's fee_application_mode determines whether platform_fee and frame_fee are deducted from the charge, added on top, or absorbed by the merchant. Fix: check the merchant's billing agreement and use the accept-a-payment guide to see the modes side-by-side.
Symptom: you provided a source_payment_method_id and a destination_payment_method_id and the funds went somewhere you didn't expect. Why: the presence of those fields is what selects the flow — providing both means the funds are moving from one account on your platform to another, not from the card to your platform. Fix: set only the fields that describe the flow you actually want.
Symptom: you set speed: "same_day" on an ACH payout and get a validation error saying same-day ACH isn't enabled. Why: same-day ACH settlement sits behind a feature flag that Frame enables per merchant — it's not on by default for every account. Fix: contact Frame to enable the same-day ACH feature flag for your account, or omit speed (or pass standard) to use normal ACH settlement.
Reference
For the full API surface, see POST/v1/transfers and the rest of the Transfers resource.