Skip to main content
A send transfers an asset from one user’s account to another user’s account holding the same asset, where both users belong to the same organization (for example, 50 USD from User A to User B). Sends follow a simple two-step flow:
  1. Create a quote on behalf of the sender.
  2. Create a transaction from that quote.
Because both accounts hold the same asset, the amount sent and the amount received are always identical — there’s no conversion or exchange rate involved.

Prerequisites

Before creating sends:
  • The sender must have completed onboarding and have the sends capability enabled.
  • The recipient must have completed onboarding and have the receives capability enabled.
  • The sender and recipient must belong to the same organization.
Recipient discovery is not provided by the Enterprise API and must be implemented by your application (for example through QR codes, contact lists, usernames, or invitation flows). Verify capabilities using List capabilities:
GET /core/users/{userId}/capabilities
{ "code": "sends", "enabled": true, "restrictions": [], "requirements": [] }

{ "code": "receives", "enabled": true, "restrictions": [], "requirements": [] }
Both accounts must be denominated in the same asset.A send moves a single asset between two same-asset accounts (e.g. USD → USD). The recipient does not need an existing balance — a freshly created, zero-balance account in that asset can receive the send.

Walkthrough

Prefer to click through the flow? See the interactive send walkthrough for a visual step-by-step guide.

Identify the sender and recipient accounts

A send involves two different users:
  • Origin account — the sender’s account.
  • Destination account — the recipient’s account.
The destination account must belong to a different ownerId than the sender. Before creating a quote, verify the recipient account exists using Get account.
GET /core/accounts/{accountId}
{
  "account": {
    "id": "d9f7a3c1-2b8e-4f5d-9c6a-1e2b3c4d5e6f",
    "label": "Jane's USD account",
    "asset": "USD",
    "balance": { "total": "100.00", "available": "100.00" }
  }
}
The send quote must be created using:
X-On-Behalf-Of: <sender userId>
This header identifies the sender and determines which user’s balances and permissions are evaluated.
Do not expose recipient ownerId values directly to end users.Instead, resolve account ownership server-side and display a friendly identifier such as a name, username, or contact entry.

Create a quote

Create a quote on behalf of the sender. The quote acts as a confirmation handle and validation step before funds move. Because both accounts hold the same asset, the amounts in the quote are always identical.
POST /core/transactions/quote
X-On-Behalf-Of: 5feba1e3-3f14-4fd9-b00d-f386df83042f
{
  "origin": {
    "type": "account",
    "id": "11de2405-1f1f-4a6e-8a39-acd97dc7f3ec"
  },
  "destination": {
    "type": "account",
    "id": "d9f7a3c1-2b8e-4f5d-9c6a-1e2b3c4d5e6f"
  },
  "denomination": {
    "asset": "USD",
    "amount": "50"
  }
}
{
  "quote": {
    "id": "b7e4d2c1-9f3a-4b5e-8d7c-2e1f3a4b5c6d",
    "expiresAt": "2026-05-29T14:02:00.000Z",
    "origin": { "asset": "USD", "amount": "50.00", "rate": "1.00" },
    "destination": { "asset": "USD", "amount": "50.00", "rate": "1.00" },
    "denomination": {
      "asset": "USD",
      "amount": "50.00",
      "rate": "1.00",
      "target": "origin"
    },
    "fees": []
  }
}
For endpoint details, see Create a quote.
Quotes have a short validity window even at a 1:1 rate. If a quote expires, transaction creation returns 404 entity_not_found — create a new quote and ask the sender to confirm again.

Create the transaction

Once the sender confirms the transfer, create the transaction from the quote. As with trades, the quoteId becomes the transactionId, allowing a single identifier to be used throughout the transfer lifecycle. Sends settle synchronously. In most cases, by the time the API responds, balances have already been updated.
POST /core/transactions
X-On-Behalf-Of: <sender userId>
{
  "quoteId": "b7e4d2c1-9f3a-4b5e-8d7c-2e1f3a4b5c6d"
}
{
  "transaction": {
    "id": "b7e4d2c1-9f3a-4b5e-8d7c-2e1f3a4b5c6d",
    "status": "processing",
    "origin": { "asset": "USD", "amount": "50.00" },
    "destination": { "asset": "USD", "amount": "50.00" }
  }
}

Notify sender and recipient

After the transaction succeeds:

Notify the sender

Display a confirmation such as:
Sent 50.00 USD to Jane Smith.
Refresh balances using Get account.

Notify the recipient

Send an in-app, push, SMS, or email notification indicating that funds were received. The recipient webhook payload contains the same transaction id returned during transaction creation, allowing notifications to be deduplicated across systems.
You now support peer-to-peer sends using the Uphold Enterprise API Suite.

Common errors

StatusCodeCauseRecommended action
409user_capability_failure (capability.code: "sends")Sender does not have the sends capability enabled.Verify onboarding status and sender capability requirements.
409user_capability_failure (capability.code: "receives")Recipient cannot receive funds.Verify recipient onboarding and capability status.
404entity_not_found (entity: "account")Destination account does not exist or is not visible to your partner relationship.Verify the recipient account ID before retrying.
404entity_not_found (entity: "quote")Quote expired or no longer exists.Create a new quote and request confirmation again.
409insufficient_balanceSender account does not have sufficient available funds.Refresh balances and prompt the sender to enter a lower amount.