Verifying a payment

Transfer statuses, finality on Solana, polling, and how to check a payment against the chain yourself.

A transfer's status tells you whether a payment landed and whether it can still be undone. This page covers each status, when a payment is safe to act on, and how to check it against the chain.

Status lifecycle

A wallet transfer, sent or received, has one of these statuses:

StatusMeaning
processingOutbound and in flight: SDP is signing and submitting it, or waiting for the chain. signature can still be null.
confirmedThe transaction landed in a block that a supermajority of the cluster voted for. signature and slot are set. Not yet irreversible.
finalizedThe block is finalized. Irreversible.
failedThe transfer never reached the network, or the network rejected it. The recipient was not paid; error says why.

POST /v1/payments/transfers waits for finality, so a successful request usually answers finalized. If the wait runs out, it answers processing, and SDP moves the transfer to confirmed, finalized or failed as the chain settles. A processing transfer that never got a signature fails after 5 minutes, unless it is waiting on a custody approval.

Inbound payments differ. A paid payment request is recorded at finalized. An observed row (from includeObserved=true) shows confirmed or failed and never finalized, because SDP rebuilds it from chain history on each read. Check its finality yourself; see Independent verification.

finalized and failed are final. Transfers that other modules create document their own lifecycle.

Finality on Solana

Act on finalized for anything irreversible: releasing custody, shipping high-value goods, posting to your general ledger. A confirmed transaction has a supermajority vote but can, rarely, still be dropped. Use it for low-stakes steps, such as a status email or a "paid" badge.

Polling cadence

SDP sends no settlement webhooks, so poll:

  • GET /v1/payments/transfers/{transferId} for one recorded transfer.
  • GET /v1/payments/transfers for a time window or one wallet's activity. See Indexing and reconciliation.

Start from these ranges:

  • Active checkout (someone is watching the payment screen): every 2–5 seconds for up to a minute, then back off.
  • Background reconciliation (no one is waiting): every 15–30 seconds, or on each worker tick.
  • After the fact: one read when your application needs the answer, with no loop.

Every poll counts against your key's rate limit. Reads with includeObserved=true also count against their own quota of 30 a minute per API key, so spread them across your open orders.

Independent verification

Once a transfer has a signature, you can check it against the network yourself:

  • signature: open it on Solana Explorer, or look it up with getSignatureStatuses on your own RPC.
  • slot: the slot the transaction landed in.
  • blockTime: the block's timestamp (ISO 8601). It is often null on transfers SDP sends; confirmedAt records when SDP saw the transaction land.
  • fee: the network fee in lamports, when known.

If you run your own indexer, compare its view of each signature with SDP's status.

Failure handling

When status is failed:

  • Read error for the reason.
  • Decide whether to try again. The failed transfer stays failed, and its Idempotency-Key replays the failure. To retry, send a new request with a new key; it creates a new transfer with its own id and signature.
  • Tell whoever needs to know: the merchant, the customer, your operations team.