Execute transfer (custody)

Executes an on-chain transfer using the exact SDP Wallet ID (id from /v1/wallets) and server-side custody signing.

POST/v1/payments/transfersRun in dashboard

Requires an Idempotency-Key: a retry with the same key and request returns the original transfer instead of sending a second one. A 200 may return a processing transfer with its signature when broadcast or confirmation is still being reconciled; do not create a replacement transfer for that payment. A native SOL transfer is refused with 409 AMOUNT_BELOW_RENT_MINIMUM, before anything is written or sent, when it pays less than the rent-exempt minimum to an address with no account or would leave the source wallet holding more than nothing but less than the minimum.

Requires an API key with the transfers.execute action.

Headers

  • x-project-id · string · min length 1 · example prj_example

    Required for dashboard sessions. API keys use their assigned project.

  • Idempotency-Key · string · required

    Use a unique 1–255 printable ASCII key per operation. Reuse it with the same request on retries. An in-flight attempt returns 409; a changed request returns 422. Retry and recovery rules.

Request body

application/json · required

Create transfer request payload for a custody-managed source wallet. This endpoint does not provision wallets.

  • projectId · string · min length 1 · example prj_example

    Project identifier for the transfer context.

  • transferId · string · min length 1

    Existing off-ramp transfer to use for the on-chain crypto deposit. The transfer must still be awaiting payment and must not already contain on-chain submission data.

  • sourceCustodyWalletId · string · required · min length 1 · example cwlt_example

    Exact SDP Wallet ID (id from GET /v1/wallets).

  • destination · string · required · example 7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU

    Destination wallet address.

  • counterpartyAccountId · string · min length 1 · example cpacct_example

    The counterparty's active Solana crypto_wallet account that destination belongs to, as a transfer batch recipient names it. The transfer record is tied to that counterparty. Its address must equal destination, and it cannot be combined with transferId.

  • token · string · required · example EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

    Token to transfer. Pass SOL for the native token, a well-known token symbol (e.g. USDC) resolved to the configured cluster's mint, or a base58 SPL mint address. Custom tokens must be specified by their on-chain mint.

  • amount · string · required · example 100.00

    Token amount in UI units (decimal string).

  • memo · string · max length 256

    Optional memo for the transfer.

Responses

  • 200 Transfer executed

    • data · object · required

      Transfer response payload.

      • transfer · object · required

        Transfer details.

        • fireblocks · object

          Native Fireblocks transfer tracking. A processing payment may await approval in Fireblocks; network fees are paid by its source vault. A missing transaction ID means submission is still being reconciled. Do not create a replacement payment while its outcome is unknown.

          • transactionId · string | null · required

          • status · string · required

          • subStatus · string | null · required

        • id · string · required · min length 1 · example xfr_example

          Transfer identifier (SDP record ID, not the on-chain signature).

        • organizationId · string · required · min length 1 · example org_example

          Organization identifier.

        • custodyWalletId · string | null · required · example cwlt_example

          Exact SDP Wallet ID associated with the persisted transfer, or null for unresolved legacy and observed rows.

        • providerWalletId · string · required · min length 1 · example privy_wallet_123

          Provider wallet ID retained as evidence; not an execution selector.

        • projectId · string · min length 1 · example prj_example

          Project identifier for the transfer.

        • type · string · required · example transfer

          Transfer type.

        • kind · string · required

          Dashboard transaction kind derived from the transfer type and originating Payments resource.

        • direction · string · required · one of inbound, outbound · example outbound

          Transfer direction.

        • status · string · required · one of pending, processing, confirmed, finalized, failed, awaiting_payment, settling, completed, canceled, expired · example confirmed

          Transfer status.

        • signature · string | null · required · example sig_example

          Solana transaction signature (tx id/hash).

        • serializedTx · string | null · required · min length 1 · example base64_tx_example

          Base64-encoded transaction payload, if available. Always null for transfer batch chunks, whose signed bytes stay server-side.

        • slot · integer | null · required · example 123456

          Slot number, if confirmed.

        • blockTime · string | null · required · format date-time · example 2025-01-01T00:00:00.000Z

          Block time, if confirmed.

        • confirmedAt · string · format date-time · example 2025-01-01T00:00:00.000Z

          When SDP confirmed the transfer. A ramp is confirmed once its delivery is verified onchain.

        • fee · integer | null · required · example 5000

          Transaction fee in lamports.

        • error · string | null · required · example Signature failed

          Error message if the transaction failed.

        • initiatedBy · object

          Initiator that triggered the transfer.

          • type · string · required · one of api_key, user, system · example api_key

            Initiator type.

          • id · string

            Initiator identifier if applicable.

          • display · string

            Human-friendly label for the initiator.

        • source · string · min length 32 · max length 44 · example So11111111111111111111111111111111111111112

          Source wallet address.

        • destination · string · min length 32 · max length 44 · example So11111111111111111111111111111111111111112

          Destination wallet address.

        • memo · string · max length 256

          Optional memo for the transfer.

        • rampsMemo · object · required

          Free-form key-value memo for offchain reconciliation of ramp transfers. At most 20 entries.

          • * · string · min length 1 · max length 256
        • token · string

          Token symbol or mint address.

        • amount · string · example 100.00

          Token amount in UI units (decimal string).

        • counterpartyId · string · example cpty_example

          Counterparty tied to the transfer record, when available.

        • counterpartyDisplayName · string · example Acme Studio

          Current display name of the counterparty tied to the transfer.

        • providerReference · string · example ramp_quote_example

          Provider quote or transaction reference used for ramp correlation.

        • deliveryMode · string · one of hosted, manual_instructions, session_widget · example session_widget

          Ramp delivery mode. Hosted flows require the customer to complete a provider-hosted UI; manual instructions require the customer to fund displayed instructions; session widgets use a provider SDK session.

        • fiatCurrency · string · example USD

          Fiat currency for the ramp leg.

        • fiatAmount · string · example 100.00

          Quoted fiat amount for the ramp leg: what the customer pays on an on-ramp, the payout quoted on an off-ramp. It never changes after the quote; an off-ramp's final payout is fiatPayout.

        • fiatPayout · object

          What the provider reports paying out once it settles an off-ramp sale. Provider-reported: SDP cannot verify a bank payout.

          • amount · string · required · example 20.82

            Fiat paid out, in display units. Differs from the quoted fiatAmount when the provider re-prices the sale at receipt.

          • currency · string · required · example USD

            ISO currency of the payout, as the provider reports it.

          • reportedAt · string · format date-time · example 2025-01-02T00:00:00.000Z

            When the provider reported the payout.

        • deliveryMismatch · object

          Present while SDP holds a provider-settled ramp in settling because the chain contradicts the provider's delivery. A new provider report clears it.

          • reason · string · required · one of provider_report_mismatch, transaction_failed, predates_transfer, not_delivered, amount_mismatch, transaction_not_found · example amount_mismatch

            Why the chain contradicts the provider: provider_report_mismatch (its report contradicts SDP's record), transaction_failed, predates_transfer (the transaction landed before the transfer), not_delivered (nothing of the quoted asset reached the quoted wallet), amount_mismatch, or transaction_not_found (no finalized transaction an hour after the report; SDP keeps checking, and a later delivery completes the transfer).

          • checkedAt · string · required · format date-time · example 2025-01-02T00:00:00.000Z

            When SDP's delivery check reached this verdict.

          • reportedAmount · string · example 20

            What the provider reported delivering, in display units.

          • observedAmount · string · example 0.5

            What the chain shows the quoted wallet received, in display units.

        • risk · object

          Optional risk evaluation for the transfer.

          • provider · string · required · example trm

            Risk scoring provider.

          • score · string · required · example 0.12

            Provider-specific risk score.

          • level · string · required · one of low, medium, high, unknown · example low

            Risk level classification.

          • evaluatedAt · string · required · format date-time · example 2025-01-01T00:00:00.000Z

            Timestamp when risk was evaluated.

        • createdAt · string · required · format date-time · example 2025-01-01T00:00:00.000Z

          Creation timestamp.

        • updatedAt · string · required · format date-time · example 2025-01-02T00:00:00.000Z

          Last update timestamp.

    • meta · object · required

      Response metadata.

      • requestId · string · required · min length 1 · example req_example

        Request identifier for tracing.

      • timestamp · string · required · format date-time · example 2025-01-01T00:00:00.000Z

        ISO 8601 timestamp.

  • 400 Bad Request

    • error · object · required

      Standard error payload.

      • code · string · required

        Machine-readable error code.

      • message · string · required

        Human-readable error message.

      • details · object

        Optional error details for debugging.

        • * · any
    • meta · object

      • requestId · string · min length 1 · example req_example

        Request identifier for tracing.

  • 401 Unauthorized

    Same fields as 400.

  • 403 Forbidden. Requires the transfers.execute action: an API key must hold it (a module's manage or execute also covers its read), and a signed-in member's organization role must include it. Without it the error is INSUFFICIENT_PERMISSIONS and error.details.action names the action. Any other 403 names its own reason.

    Same fields as 400.

  • 404 Not Found

    Same fields as 400.

  • 409 Conflict

    Same fields as 400.

  • 422 Unprocessable Entity

    Same fields as 400.

  • 500 Internal Server Error

    Same fields as 400.

  • 503 Service Unavailable

    Same fields as 400.

Example request

curl -X POST 'https://api.solana.com/v1/payments/transfers' \
  -H "Authorization: Bearer $SDP_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": "prj_example",
    "sourceCustodyWalletId": "cwlt_example",
    "destination": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
    "token": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "amount": "100.00"
  }'

Example responses

{
  "data": {
    "transfer": {
      "fireblocks": {
        "transactionId": "transaction_example",
        "status": "example",
        "subStatus": "example"
      },
      "id": "xfr_example",
      "organizationId": "org_example",
      "custodyWalletId": "cwlt_example",
      "providerWalletId": "privy_wallet_123",
      "projectId": "prj_example",
      "type": "transfer",
      "kind": "example",
      "direction": "outbound",
      "status": "confirmed",
      "signature": "sig_example",
      "serializedTx": "base64_tx_example",
      "slot": 123456,
      "blockTime": "2025-01-01T00:00:00.000Z",
      "confirmedAt": "2025-01-01T00:00:00.000Z",
      "fee": 5000,
      "error": "Signature failed",
      "initiatedBy": {
        "type": "api_key"
      },
      "source": "So11111111111111111111111111111111111111112",
      "destination": "So11111111111111111111111111111111111111112",
      "rampsMemo": {
        "invoice": "INV-123",
        "po": "PO-9"
      },
      "amount": "100.00",
      "counterpartyId": "cpty_example",
      "counterpartyDisplayName": "Acme Studio",
      "providerReference": "ramp_quote_example",
      "deliveryMode": "session_widget",
      "fiatCurrency": "USD",
      "fiatAmount": "100.00",
      "fiatPayout": {
        "amount": "20.82",
        "currency": "USD",
        "reportedAt": "2025-01-02T00:00:00.000Z"
      },
      "deliveryMismatch": {
        "reason": "amount_mismatch",
        "checkedAt": "2025-01-02T00:00:00.000Z",
        "reportedAmount": "20",
        "observedAmount": "0.5"
      },
      "risk": {
        "provider": "trm",
        "score": "0.12",
        "level": "low",
        "evaluatedAt": "2025-01-01T00:00:00.000Z"
      },
      "createdAt": "2025-01-01T00:00:00.000Z",
      "updatedAt": "2025-01-02T00:00:00.000Z"
    }
  },
  "meta": {
    "requestId": "req_example",
    "timestamp": "2025-01-01T00:00:00.000Z"
  }
}

Error responses use the standard error shape.

Is this page helpful?