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.


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 typeBillable event
Cardtransfer.charge.card
ACHtransfer.charge.ach

The destination_payment_method_id is optional for charge flows:

destination_payment_method_idFunds destination
OmittedFunds go to the merchant (platform)
ProvidedFunds go to the account that owns the payment method

The fee_application_mode on the billing agreement determines how fees are applied:

ModeBehavior
deductThe card is charged exactly amount. platform_fee and frame_fee are deducted from that, so the payee receives amount − total_fees.
add_onThe 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 typeBillable event
ACH bank accounttransfer.payout.ach
Debit cardtransfer.payout.push_to_card

The fee_application_mode on the billing agreement determines how fees are handled:

ModeBehavior
deductplatform_fee and frame_fee are deducted from the payout amount. The payee receives amount − total_fees
absorbThe 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

StatusDescription
pendingTransfer has been created and is awaiting processing
completedFunds have been successfully moved
failedTransfer could not be completed. See failure_reason for details
reversedA completed transfer has been reversed
canceledTransfer was canceled before processing
blockedTransfer is blocked, typically pending a compliance review

The Transfer object

Attributes
idstringoptional

Unique identifier for the transfer.

objectstringoptional

Always transfer.

statusenumoptional

Current status. One of pending, completed, failed, reversed, canceled, or blocked.

amountintegeroptional

Requested transfer amount in the smallest currency unit (e.g. cents). 10000 represents $100.00.

currencystringoptional

Three-letter ISO currency code in uppercase (e.g. USD).

platform_feeintegeroptional

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_feeintegeroptional

Frame's processing fee for this transfer, in cents. Always additive on top of platform_fee.

total_feesintegeroptional

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_amountintegeroptional

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.

net_amountintegeroptional

Amount received by the payee in cents. In deduct mode, equals gross_amount − total_fees. In add_on and absorb modes, equals amount.

descriptionnullable stringoptional

Optional description provided at creation.

failure_reasonnullable stringoptional

Human-readable reason when status is failed, otherwise null.

charge_intentnullable stringoptional

ID of the associated charge intent for charge flows, otherwise null.

payoutnullable stringoptional

ID of the associated payout for payout flows, otherwise null.

billing_agreementstringoptional

ID of the billing agreement used to calculate fees.

source_payment_methodnullable objectoptional

The payment method charged in charge flows. Contains id, object, type, status, livemode, created, and updated. null for payout flows.

destination_payment_methodnullable objectoptional

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.

metadatadictionaryoptional

A set of key-value pairs you can attach to the transfer for your own reference.

livemodebooleanoptional

true if the transfer exists in live mode, false for test mode.

createdintegeroptional

Unix timestamp of when the transfer was created.

THE TRANSFER OBJECT
{
  "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
amountinteger

Amount in the smallest currency unit (e.g. 10000 for $100.00). Must be greater than 0.

account_idstring

ID of the account associated with the transfer.

currencystringoptional

ISO currency code (e.g. USD). Defaults to USD.

source_payment_method_idstringoptional

Required for charge flows. The payment method to charge. Omit for payout flows.

destination_payment_method_idstringoptional

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.

descriptionstringoptional

Arbitrary description for your records.

metadatadictionaryoptional

Key-value pairs to attach to the transfer.

Returns

Returns the created transfer object.

POST/v1/transfers
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"
}'
RESPONSE
{
  "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.

POST/v1/transfers
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"
}'
RESPONSE
{
  "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
idstring

The ID of the transfer to retrieve.

Returns

Returns the transfer object.

GET/v1/transfers/:id
curl --request GET \
  --url https://api.framepayments.com/v1/transfers/e36c1cc2-d9f0-44db-a522-12b0aab990db \
  --header 'Authorization: Bearer API_KEY'
RESPONSE
{
  "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
per_pageintegeroptional

Number of results per page.

pageintegeroptional

Page number.

Returns

Returns a paginated list of transfer objects.

GET/v1/transfers
curl --request GET \
  --url https://api.framepayments.com/v1/transfers \
  --header 'Authorization: Bearer API_KEY'
RESPONSE
{
  "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:

RequirementApplies toDetails
Active billing agreementAll transfersThe 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 planPayout flowsThe merchant must have a fee plan configured for the payout method (ach or push_to_card).
Processing fee planCharge flowsThe merchant must have a default processing fee plan.
KYC/KYB verified accountPayout flowsThe account must have a verified identity. Individual accounts require a verified kyc_verification requirement; business accounts require kyb_verification. See KYC.

Webhooks

EventTriggered when
transfer.createdA transfer is successfully created
transfer.completedThe transfer completes (payout confirmed by processor)
transfer.failedThe transfer fails. The failure_reason field on the object explains why

Event payload

WEBHOOK EVENT
{
  "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
  }
}