Transfers
Transfers represent the movement of funds associated with an account. frameOS supports two flows:
- Charge flow — a source payment method (card or ACH) is charged and funds move to the merchant's subaccount.
- Payout flow — funds are pushed directly to an account's payment method (ACH or debit card) with no source payment method required.
Transfers are created synchronously. For payout flows, the underlying payout is processed asynchronously and the transfer status is updated once the processor responds.
Before creating a transfer, make sure your merchant has an active billing agreement and the appropriate fee plans configured. See prerequisites for details.
Transfer flows
Charge flow
Provide a source_payment_method_id to charge the payer's card or bank account. The billable event type is resolved automatically based on the payment method type:
| Source type | Billable event |
|---|---|
| Card | transfer.charge.card |
| ACH | transfer.charge.ach |
The destination_payment_method_id is optional for charge flows:
destination_payment_method_id | Funds destination |
|---|---|
| Omitted | Funds go to the merchant (platform) |
| Provided | Funds go to the account that owns the payment method |
The fee_application_mode on the billing agreement determines how fees are applied:
| Mode | Behavior |
|---|---|
deduct | The card is charged exactly amount. platform_fee and frame_fee are deducted from that, so the payee receives amount − total_fees. |
add_on | The card is charged a grossed-up total that covers amount plus all fees. The payee receives the full amount. |
Payout flow
Omit source_payment_method_id and provide only destination_payment_method_id. Funds are pushed to the account's payment method. The billable event type is resolved automatically:
| Destination type | Billable event |
|---|---|
| ACH bank account | transfer.payout.ach |
| Debit card | transfer.payout.push_to_card |
The fee_application_mode on the billing agreement determines how fees are handled:
| Mode | Behavior |
|---|---|
deduct | platform_fee and frame_fee are deducted from the payout amount. The payee receives amount − total_fees |
absorb | The payee receives the full amount. The merchant absorbs both platform_fee and frame_fee |
Payout processing is asynchronous. The transfer starts as pending and transitions to completed or failed once the processor responds.
Statuses
| Status | Description |
|---|---|
| pending | Transfer has been created and is awaiting processing |
| completed | Funds have been successfully moved |
| failed | Transfer could not be completed. See failure_reason for details |
| reversed | A completed transfer has been reversed |
| canceled | Transfer was canceled before processing |
| blocked | Transfer is blocked, typically pending a compliance review |
The Transfer object
Attributes
Unique identifier for the transfer.
Always transfer.
Current status. One of pending, completed, failed, reversed, canceled, or blocked.
Requested transfer amount in the smallest currency unit (e.g. cents). 10000 represents $100.00.
Three-letter ISO currency code in uppercase (e.g. USD).
The fee earned by the platform on this transfer, in cents. This is the amount configured in the fee plan item for the matching billable event.
Frame's processing fee for this transfer, in cents. Always additive on top of platform_fee.
Sum of platform_fee and frame_fee in cents. In deduct mode, this is the total deducted from the transaction. In absorb and add_on modes, this reflects the fees applied but they are not deducted from the payee's proceeds.
Gross transaction amount in cents. For charge flows in deduct mode, equals amount. For add_on mode, equals the grossed-up amount charged to the sender. For payout flows, equals amount.
Amount received by the payee in cents. In deduct mode, equals gross_amount − total_fees. In add_on and absorb modes, equals amount.
Optional description provided at creation.
Human-readable reason when status is failed, otherwise null.
ID of the associated charge intent for charge flows, otherwise null.
ID of the associated payout for payout flows, otherwise null.
ID of the billing agreement used to calculate fees.
The payment method charged in charge flows. Contains id, object, type, status, livemode, created, and updated. null for payout flows.
The payment method funds are sent to in payout flows. Contains id, object, type, status, livemode, created, and updated. null when omitted in charge flows.
A set of key-value pairs you can attach to the transfer for your own reference.
true if the transfer exists in live mode, false for test mode.
Unix timestamp of when the transfer was created.
{
"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": 10000,
"description": "Weekly payout",
"failure_reason": null,
"charge_intent": null,
"payout": null,
"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
}
Create a transfer
Creates a new transfer. You must provide either source_payment_method_id (charge flow) or destination_payment_method_id (payout flow). Providing neither returns a validation error.
Parameters
Amount in the smallest currency unit (e.g. 10000 for $100.00). Must be greater than 0.
ID of the account associated with the transfer.
ISO currency code (e.g. USD). Defaults to USD.
Required for charge flows. The payment method to charge. Omit for payout flows.
Required for payout flows (must be ACH or debit card). Optional for charge flows — when provided, funds are routed to the account that owns the payment method; when omitted, funds go to the merchant.
Arbitrary description for your records.
Key-value pairs to attach to the transfer.
Returns
Returns the created transfer object.
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": "c1a4a27f-d6e4-46e2-9557-fd5faaa31e7d",
"destination_payment_method_id": "2a769159-83b7-4b78-8a07-3e5891a414d2",
"description": "Weekly payout"
}'
{
"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": 10000,
"description": "Weekly payout",
"failure_reason": null,
"charge_intent": null,
"payout": null,
"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
}
Charge flow example
To create a charge flow transfer, provide a source_payment_method_id instead of a destination_payment_method_id. The charge is processed synchronously and a charge_intent is created.
curl --request POST \
--url https://api.framepayments.com/v1/transfers \
--header 'Authorization: Bearer API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"amount": 5000,
"account_id": "c1a4a27f-d6e4-46e2-9557-fd5faaa31e7d",
"source_payment_method_id": "pm_xyz789",
"currency": "USD",
"description": "Product purchase"
}'
{
"id": "f47a2dd3-e0b1-55ec-b633-23c1bbc101ec",
"object": "transfer",
"status": "pending",
"amount": 5000,
"currency": "USD",
"platform_fee": 200,
"frame_fee": 214,
"total_fees": 414,
"gross_amount": 5000,
"net_amount": 4586,
"description": "Product purchase",
"failure_reason": null,
"charge_intent": "ci_abc123",
"payout": null,
"billing_agreement": "b37da62b-c233-4358-967a-7910656fb94f",
"source_payment_method": {
"id": "pm_xyz789",
"object": "payment_method",
"type": "card",
"status": "active",
"livemode": false,
"created": 1773398080,
"updated": 1773398080
},
"destination_payment_method": null,
"metadata": {},
"livemode": false,
"created": 1773415510
}
Retrieve a transfer
Retrieves the details of an existing transfer by its ID.
Parameters
The ID of the transfer to retrieve.
Returns
Returns the transfer object.
curl --request GET \
--url https://api.framepayments.com/v1/transfers/e36c1cc2-d9f0-44db-a522-12b0aab990db \
--header 'Authorization: Bearer API_KEY'
{
"id": "e36c1cc2-d9f0-44db-a522-12b0aab990db",
"object": "transfer",
"status": "completed",
"amount": 10000,
"currency": "USD",
"platform_fee": 100,
"frame_fee": 15,
"total_fees": 115,
"gross_amount": 10000,
"net_amount": 10000,
"description": "Weekly payout",
"failure_reason": null,
"charge_intent": null,
"payout": null,
"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
}
List transfers
Returns all transfers for the authenticated merchant, ordered by most recently created. Results are scoped to the current environment (test vs. live mode).
Parameters
Number of results per page.
Page number.
Returns
Returns a paginated list of transfer objects.
curl --request GET \
--url https://api.framepayments.com/v1/transfers \
--header 'Authorization: Bearer API_KEY'
{
"data": [
{
"id": "e36c1cc2-d9f0-44db-a522-12b0aab990db",
"object": "transfer",
"status": "completed",
"amount": 10000,
"currency": "USD",
"platform_fee": 100,
"frame_fee": 15,
"total_fees": 115,
"gross_amount": 10000,
"net_amount": 10000,
"description": "Weekly payout",
"failure_reason": null,
"charge_intent": null,
"payout": null,
"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
}
],
"meta": {
"current_page": 1,
"total_pages": 1,
"total_count": 1
}
}
Prerequisites
Before creating a transfer the following must be in place:
| Requirement | Applies to | Details |
|---|---|---|
| Active billing agreement | All transfers | The merchant must have an active billing agreement. A merchant-level agreement applies to all accounts unless an account-specific one exists. See billing. |
| Payout fee plan | Payout flows | The merchant must have a fee plan configured for the payout method (ach or push_to_card). |
| Processing fee plan | Charge flows | The merchant must have a default processing fee plan. |
| KYC/KYB verified account | Payout flows | The account must have a verified identity. Individual accounts require a verified kyc_verification requirement; business accounts require kyb_verification. See KYC. |
Webhooks
| Event | Triggered when |
|---|---|
transfer.created | A transfer is successfully created |
transfer.completed | The transfer completes (payout confirmed by processor) |
transfer.failed | The transfer fails. The failure_reason field on the object explains why |
Event payload
{
"type": "transfer.created",
"data": {
"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": 10000,
"livemode": false,
"created": 1773415510
}
}