The lifecycle
UseGET /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 returnsreceipt.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.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
- Read the original request ID. A timeout is not proof that execution failed.
- If there is a transaction, follow that transaction to completion or failure.
- If the state is unresolved, retain it and investigate; do not automatically repeat execution
even if the authorization still reads
approved. - Create a new intent only after establishing the original outcome and confirming the business action still needs payment. Preserve the association between both intents.
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
KeepREQUIRES_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. CatchContoError, 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 return409 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.