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

Frame's processing fee is calculated against the charged amount. How fees affect the payee depends on the billing plan's fee_application_mode:

ModeBehavior
deductFees are deducted from the transfer amount. The sender is charged amount as-is
add_onThe sender is charged a grossed-up amount so that after Frame deducts its fee, the full amount reaches the merchant

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

For payout flows, net_amount always equals the requested amount — the payee receives the full amount. Frame's frame_fee is charged to the merchant separately.

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).

net_amountintegeroptional

Amount received by the payee in cents. For payout flows, always equals amount. For charge flows, may be reduced by fees depending on the billing plan.

frame_feeintegeroptional

Frame's fee for this transfer in cents. For payout flows this is charged to the merchant, not deducted from the payee.

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",
  "net_amount": 10000,
  "frame_fee": 100,
  "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",
  "net_amount": 10000,
  "frame_fee": 100,
  "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",
  "net_amount": 4789,
  "frame_fee": 211,
  "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",
  "net_amount": 10000,
  "frame_fee": 100,
  "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",
      "net_amount": 10000,
      "frame_fee": 100,
      "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",
    "net_amount": 10000,
    "frame_fee": 100,
    "livemode": false,
    "created": 1773415510
  }
}