Skip to main content
Transfers move existing funds from one participant or group to one or more recipients. They are zero-sum: the source balance decreases by the total amount credited to all recipients. You might use them for peer-to-peer gifting, marketplace payouts with platform fees, or distributing a pool across multiple participants.

Creating a Transfer

POST /v1/transfers
{
  "program_id": "program-uuid",
  "source_external_id": "alice",
  "asset_id": "asset-uuid",
  "description": "Gift to Bob",
  "recipients": [
    {"external_id": "bob", "amount": "50"}
  ]
}
FieldRequiredDescription
program_idYesProgram context
asset_idYesWhich asset to transfer
source_external_idOne ofParticipant sending funds (by your external ID). Mutually exclusive with source_group_id and source_participant_id.
source_participant_idOne ofParticipant sending funds (by Scrip UUID). Mutually exclusive with source_external_id and source_group_id.
source_group_idOne ofGroup sending funds. Mutually exclusive with source_external_id and source_participant_id.
recipientsYesArray of 1-100 recipients, each with external_id, participant_id, or group_id and an amount
descriptionYesReason for the transfer (1-500 characters)
idempotency_keyNoPrevents duplicate transfers on retry. Same key + different payload returns 409.
The source’s available balance is debited for the total amount, and each recipient’s available balance is credited. The entire transfer is atomic: if any part fails, nothing moves.

Multi-Recipient Transfers

Split funds across multiple recipients in a single request:
POST /v1/transfers
{
  "program_id": "program-uuid",
  "source_external_id": "alice",
  "asset_id": "asset-uuid",
  "description": "Marketplace payout with platform fee",
  "recipients": [
    {"external_id": "bob", "amount": "95"},
    {"external_id": "platform_account", "amount": "5"}
  ]
}
Up to 100 recipients per transfer. This covers marketplace payouts with platform fees, prize splits, revenue sharing, and similar distributions.

Identifying Participants and Groups

The source and recipients can be identified by external ID, Scrip UUID, or group ID. Each identifier is mutually exclusive. Provide exactly one per source or recipient. For the source, use source_external_id, source_participant_id, or source_group_id. For recipients, use external_id, participant_id, or group_id on each entry.
POST /v1/transfers
{
  "program_id": "program-uuid",
  "source_group_id": "team-pool-uuid",
  "asset_id": "asset-uuid",
  "description": "Team bonus distribution",
  "recipients": [
    {"external_id": "alice", "amount": "200"},
    {"external_id": "bob", "amount": "200"},
    {"group_id": "reserve-fund-uuid", "amount": "100"}
  ]
}

LOT-Mode Assets

For LOT-mode assets, transfers consume lots from the source in FIFO order and create new lots for each recipient. The new lots get fresh created_at timestamps, meaning vintage resets on transfer. Source lot expiration dates do not carry over to the recipient.

Response

The response includes a journal_entry_id for tracing the transfer in the ledger, along with computed totals.
{
  "journal_entry_id": "uuid",
  "asset_id": "asset-uuid",
  "source_id": "uuid",
  "total_amount": "300.50",
  "recipient_count": 3
}

Transfer vs. Credit vs. Adjust

OperationWhat it doesUse case
TransferMoves existing funds from source to recipientsP2P gifting, marketplace payouts
CREDIT (rule action)Creates new funds (or draws from program wallet)Rewards, bonuses, earning points
Adjust (API)Manual credit or debit on a single participantCustomer service, corrections

Requirements

  • All recipients must be ACTIVE. The source can be ACTIVE or CLOSED (allowing fund recovery from closed accounts).
  • Program must be ACTIVE (not SUSPENDED or ARCHIVED)
  • Source must have sufficient available balance for the total transfer amount. If insufficient, the entire transfer rolls back.
  • Source and recipient cannot be the same entity
  • Idempotency keys are scoped per program. Replaying a request with the same key and parameters returns the original result. Replaying with the same key but different parameters returns a 409 conflict.