Skip to main content
A payment request is an intent to spend. Authorization permits the next step; it does not prove funds moved. A transaction records execution. Retain the request ID before executing, then use it to reconcile the outcome.

The lifecycle

Use GET /api/sdk/payments/{requestId} or conto.payments.status(requestId) with the same agent key. Status reads require transactions:read. The status endpoint uses lowercase values; authorization responses use uppercase values. Do not compare the two interchangeably.

What proves settlement?

Execution returns receipt.transactionId and receipt.settlementMode. live means an onchain transfer, including testnet; test means simulated settlement. New test receipts omit transaction hashes and explorer URLs. Preserve the receipt and request ID. Status and transaction endpoints repeat settlementMode; unknown means execution evidence is absent or the legacy record cannot establish the mode. Never infer onchain settlement from completed or a legacy hash alone. A simulated record has no blockchain confirmation time or block number. For an onchain flow, wait for transaction.status: "completed" and check the intended chain. A hash alone, an approval, or HTTP 200 is not confirmation. For a sandbox flow, a completed test receipt demonstrates the API workflow without a blockchain transfer.

Bounded polling

Call this helper after submission, or after an uncertain result. It only reads state. A non-processing state returns control to your application, including review, expiry, and denial. Configure the SDK request timeout too: an in-flight HTTP call can finish after the polling deadline.
If a read fails with 429, honor Retry-After; resume later with the same request ID. A polling deadline or read failure does not cancel the payment. See rate limits.

Recovery recipes

Execution timed out

  1. Read the original request ID. A timeout is not proof that execution failed.
  2. If there is a transaction, follow that transaction to completion or failure.
  3. If the state is unresolved, retain it and investigate; do not automatically repeat execution even if the authorization still reads approved.
  4. Create a new intent only after establishing the original outcome and confirming the business action still needs payment. Preserve the association between both intents.
A repeated execute can return 400 INVALID_STATUS after completion or 409 ALREADY_EXECUTED for an execution conflict. Reconcile the original request in either case. Persist your business action ID, idempotency key, Conto request ID, execution attempt, and receipt durably. A restarted worker must be able to discover an earlier execution attempt.

A human must approve

Keep REQUIRES_APPROVAL requests pending in your application. An authorized reviewer decides in the configured approval workflow. Check the same request ID after review: an approved decision is not a settlement receipt, and the workflow may already have begun execution. Only perform a next write when its state and your stored attempt history permit it.

The SDK throws ACTION_REQUIRED

HTTP 402 rejects the SDK promise. Catch ContoError, preserve error.requestId, and present error.actionUrl. After the customer finishes, read the original request instead of creating another payment. See the request example.

External confirmation returns a conflict

Send through your external signer only after approval. Confirm using the request ID, final hash, and the approval token when one was issued. After human workflow approval, the token can be omitted. Repeated confirmation does not duplicate recorded spend but can return 409 ALREADY_CONFIRMED. Compare the returned txHash with your saved transfer and follow statusUrl. If the hashes differ, stop and investigate. Never send a second transfer to resolve a confirmation error.

The wallet has insufficient funds

Inspect the intended wallet’s address, network, currency, and available balance. Funding another wallet or chain does not repair this request. After funding, re-read the request and check expiry and prior execution evidence before deciding whether to resume or request new authorization.

A webhook is missing or repeated

Use the payment status endpoint to reconcile. Verify webhook signatures and persist accepted events before returning success. Handle duplicate or out-of-order delivery without creating a new payment; the current resource state should determine your application’s next action. Follow webhook delivery and deduplication.

Next steps

Use server integration examples to connect recovery to an authenticated application route, and exercise these paths with payment tests.