How payments work on SDP
Custody wallets, tokens, amounts, fees and the transfer record behind every SDP payment.
An SDP payment moves tokens from one of your custody wallets to a Solana address, and SDP records it as a transfer. This page covers the pieces the rest of the section builds on.
Custody wallets
Every payment leaves from a custody wallet in your organization, optionally scoped to a project. A custody provider holds the wallet's key, and SDP asks that provider to sign. Limit what an API key can do with a wallet through grants and wallet access.
Create wallets first: see Set Up Wallets. A transfer request names its source by the wallet's SDP id (cwlt_…) in sourceCustodyWalletId. Responses return that id as custodyWalletId and keep the provider's own wallet id in providerWalletId. The destination is the recipient's Solana address.
Tokens and amounts
Pass token as SOL for native SOL, a well-known symbol such as USDC, or an SPL mint address. Pass a custom token by its mint. SDP resolves a symbol to its mint on your project's cluster and stores the mint on the transfer. The token filter on GET /v1/payments/transfers takes the same forms, and a well-known token matches whether you filter by symbol or by mint.
Amounts are decimal strings in whole-token units: "100.00" is 100 tokens, whatever the mint's decimals. Every amount you send SDP takes this form, and SDP converts it to base units when it builds the transaction. Wallet balance responses return both forms: amount in base units and uiAmount as a decimal string.
Transfer execution
POST /v1/payments/transfers runs the whole transfer on the server. SDP builds the transaction, has the source wallet's custody provider sign it, submits it to your project's cluster, and waits for the cluster to finalize it before it answers.
Fees and sponsorship
SDP pays the network fee, and the rent for any new recipient token account, on each transfer it signs from a Privy wallet. Those wallets need only the tokens they send, with no SOL for fees. Sponsorship has limits: when the sponsor can't pay, SDP refuses the transfer rather than charge the source wallet. A provider that submits its own transfers pays their fees from its own account, and SDP does not sponsor them.
The transfer data model
Every transfer SDP sends or records is a Transfer. The fields most flows use:
| Field | Meaning |
|---|---|
id | The SDP transfer id (xfr_…). Use it in API paths. |
status | processing, confirmed, finalized or failed for a wallet transfer. See Verifying a payment. |
direction | outbound (you paid) or inbound (you were paid). |
source, destination | Solana addresses. |
counterpartyId | The counterparty (cpty_…) the transfer is tied to, such as a transfer batch recipient or a transfer sent with counterpartyAccountId. |
token, amount | What moved and how much. token is a mint address (some older records hold a symbol); amount is a decimal string such as "100.00". |
memo | Your note, up to 256 characters. SDP stores it; it is not written on chain. See Payment with memo. |
signature | The Solana transaction signature, once there is one. Unique across SDP transfers. |
slot, blockTime, confirmedAt | The slot the transaction landed in, its block time, and when SDP saw it land. blockTime is often null on transfers SDP sends. |
fee | The network fee in lamports, when known. |
error | Why the transfer failed. |
An outbound transfer starts at processing, and a successful POST usually answers finalized. See Verifying a payment for every status and what it means.
What SDP does and does not give you
You get what you need to send, track and reconcile payments transfer by transfer: status reads, filtered lists, wallet balances, Idempotency-Key replay, and a unique signature per transfer (see Basic payment). The public API has no checkout session or invoice object. Accept payments covers the dashboard's payment links and how to build checkout on transfers.
Related
- Payments API reference: every payments endpoint.
- End-to-end payment flow: the same lifecycle as a step-by-step tutorial.