Payment with memo

Attach an order ID, invoice number, or customer reference to an SDP transfer.

The memo field on POST /v1/payments/transfers carries an arbitrary UTF-8 string (up to 256 characters) alongside the on-chain transfer. Memos are persisted on the SDP Transfer record and surface in list and read responses, so your indexer can map each transfer back to a row in your product database.

When to use a memo

Use a memo when you need a free-form correlation token that your backend already knows at request time:

  • Order or invoice IDsorder_2026-05-14_4837 so the inbound transfer ties to a checkout row.
  • Customer references — internal customer or account identifiers for support and reconciliation.
  • Run identifiers — a payout-batch ID shared across many outbound transfers in the same disbursement.

Memos are stored by SDP. They are not automatically attached as a Solana memo-program instruction; if you need an on-chain memo that block explorers display, that has to be handled at the transaction level (see the trade-offs section below).

API usage

curl -X POST https://api.solana.com/v1/payments/transfers \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "source": "wal_example",
    "destination": "7xKXz...9fGh",
    "token": "9aBCd...4eEf",
    "amount": "100.00",
    "memo": "order_2026-05-14_4837"
  }'
const response = await fetch(
  "https://api.solana.com/v1/payments/transfers",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer sk_test_...",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      source: "wal_example",
      destination: "7xKXz...9fGh",
      token: "9aBCd...4eEf",
      amount: "100.00",
      memo: "order_2026-05-14_4837",
    }),
  }
);
const { data } = await response.json();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.solana.com/v1/payments/transfers"))
    .header("Authorization", "Bearer sk_test_...")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("""
        {
          "source": "wal_example",
          "destination": "7xKXz...9fGh",
          "token": "9aBCd...4eEf",
          "amount": "100.00",
          "memo": "order_2026-05-14_4837"
        }"""))
    .build();

The memo is preserved on the transfer record:

{
  "id": "xfr_...",
  "memo": "order_2026-05-14_4837",
  "status": "finalized",
  "signature": "5xR1...",
  ...
}

Memo limits: z.string().max(256). UTF-8 is accepted; trim or sanitize on the way in if your downstream systems are stricter.

Trade-offs vs. Solana Pay reference accounts

For accept flows, Solana Pay reference accounts are an alternative correlation mechanism: you generate a unique pubkey per order and include it in the on-chain transfer as a reference. The advantage is on-chain provenance — anyone can verify the link without trusting SDP's database — and the ability for the payer to construct the transfer themselves from a Solana Pay URL.

SDP's Prepare endpoint accepts a referenceAddress field as a roadmap hook for Solana Pay-style correlation, but does not yet attach it on-chain or expose it on inbound transfer records — for now use memo for SDP-side correlation, or read the reference directly from the transaction via Solana RPC. Use Accept overview and Indexing and reconciliation for the inbound side.

Rule of thumb: memos are simpler when you initiate the transfer (server-side payouts, internal moves), references are stronger when a third party initiates the transfer (customer checkout, donations).

Indexing implications

Memos are returned by GET /v1/payments/transfers and GET /v1/payments/transfers/{id}, so your reconciliation worker can filter by date / direction / token and then match each row to your order table by memo. See Indexing and reconciliation for query patterns.

Is this page helpful?