Payments API
The payments API allows agents to request authorization and execute stablecoin payments.Payment SDK routes enforce explicit API-key scopes. Reading payment status requires
transactions:read; requesting, approving, and executing payments require their corresponding
payments:request, payments:approve, and payments:execute scopes.Credential-gated checkout relay alpha
The default-off checkout relay is a separate hard-control path for supported merchant checkouts. An admin SDK key withmerchant:purchase can issue and inspect a five-minute grant at:
POST /api/sdk/checkout-relay/grantsGET /api/sdk/checkout-relay/grants/{grantId}
Overview
The payment flow has two steps:- Request - Request authorization and policy evaluation
- Execute - Execute the approved payment onchain
autoExecute: true to request and execute in a single API call. You can also use the SDK convenience method pay() to do both in one call.
Choose The Right Flow
Managed wallets are provisioned and executed exclusively through Privy. The payment request route
selects only Privy-backed managed wallets; self-custodied wallets must use the external-wallet
flow. A managed wallet can be organization-controlled or Conto-managed. Both use the same
request -> execute API, while their root ownership and key-access boundaries differ. See Custody
Modes.payments.request()
Request authorization for a payment. This evaluates policies without executing.Parameters
Use
context.department and context.project when the payment should count against a scoped
budget. These dimensions are persisted on the resulting transaction and evaluated together with
the payment category.
Set context.recipientCountry to a two-letter ISO country code when geographic policy evaluation
needs the recipient jurisdiction. Conto trims the value, normalizes it to uppercase, and includes
it in the idempotency fingerprint for the request.
External wallet users: If your agent controls its own wallet keys and uses the
/api/sdk/payments/approve endpoint instead, chainId is a required parameter. See the Agent
Skills guide (OpenClaw and Hermes) for the external-wallet flow.If you include
context.invoice, Conto links the invoice details to the payment for
reconciliation and approval review. Supported invoice fields are vendorId, vendorAddress,
id, hash, sourceUrl, payload, expectedAmount, currency, and dueDate. Delta
verification workflows and payment.executed webhook payloads prefer this typed invoice record
for new requests. For a full setup and live test example, see Delta Verification
Setup and Delta Smoke Test.Delta access is currently enabled by Conto during onboarding. If you want to use this flow,
contact sales@conto.finance.
If an approval workflow matches any non-denied request, Conto opens the approval request
immediately and includes
approvalRequestId in the API response. This includes workflows that
intentionally gate otherwise policy-approved payments. If the payment controls require approval
and no custom workflow matches, Conto still opens an actionable review and returns its
approvalRequestId.External Wallet Approve/Confirm Flow
If your agent holds the signing keys, use the external-wallet flow instead ofpayments.execute():
- Call
POST /api/sdk/payments/approveto evaluate policy and receive anapprovalToken - Submit the onchain transfer through your own signer or wallet integration
- Call
POST /api/sdk/payments/{requestId}/confirmwith the finaltxHash, plus theapprovalTokenwhen the original/approveresponse returned one
Confirmation atomically claims an approved external-wallet payment before creating the transaction
record and updating spend tracking. A repeated confirmation for the same request returns a
conflict instead of creating duplicate ledger effects.
If the
senderAddress has not been seen before, Conto auto-creates an external wallet record for
that address and links it to the agent’s organization. That record still counts toward the
organization’s wallet limit, so approval can fail with WALLET_LIMIT_REACHED when the org is
already at capacity.The external-wallet
approve flow accepts the same optional context.invoice object as
payments.request() and stores the same typed invoice fields on the resulting PaymentRequest.If an approval workflow matches,
/api/sdk/payments/approve returns requiresHumanApproval: true
and includes approvalRequestId in the response instead of issuing an approvalToken. After that
workflow approves the payment, POST /api/sdk/payments/{requestId}/confirm can be called with
just the final txHash. Policy-required reviews use the same response shape even when no custom
workflow matches, so every review remains actionable.Agent-skill approval decisions
OpenClaw can list pending reviews withGET /api/sdk/approval-requests?type=payment&status=PENDING
and submit the assigned human owner’s explicit decision after the owner provides the matching
one-time token from their independently delivered approval notification:
payments:approve, but the agent SDK key alone cannot create a decision. The
one-time token must match the approval request, assigned owner, and approve/reject action. The route
still enforces that person’s transaction-approval permission plus every workflow eligibility and
sequencing rule. When the decision completes the workflow, Conto automatically sends managed-wallet
payments and returns receiptUrl. External wallets receive a nextAction payload containing the
exact transfer and tokenless confirmation handoff. A retry of an already-recorded matching decision
does not require a second token.
Response
0.1.0 request response uses requestId and executeUrl for the two-step flow. For
autoExecute: true, an approved request returns status: "EXECUTED" and the flat execution
object. reasons, violations, hint, and context explain policy decisions without exposing
provider diagnostics or stored policy records.
Payment responses include
currency (for example, USDC, USDT, USDC.e, or pathUSD) so the
caller can reconcile the requested amount with the selected wallet network.Currency depends on chain: The
currency field reflects the stablecoin used on the wallet’s
blockchain. On Base, Ethereum, Arbitrum, and Polygon, both USDC and USDT are supported. On
Tempo Testnet, it is pathUSD. On Tempo Mainnet, it is USDC.e. The amount is always denominated
in the stablecoin configured for the payment.Idempotent Retries
UseidempotencyKey when your caller may retry the same payment request because of network timeouts or uncertain client state.
- Same
idempotencyKey+ same request payload: returns the originalrequestIdand current next action - Same
idempotencyKey+ different request payload: returns HTTP409withcode: "IDEMPOTENCY_CONFLICT" - Different
idempotencyKey: creates a new payment request
Example
payments.execute()
Execute an approved payment request. Immediately before custody dispatch, Conto re-evaluates the full current policy set. A newly denied payment is not sent and its reservation is released. If the policy service cannot complete the evaluation, execution fails closed.payments.execute() rechecks ownership and active spending limits before submitting the payment.
Successful responses include the stable Conto transaction ID needed for reconciliation.Parameters
Response
A
processing response means the payment was submitted and should be checked with
payments.status(requestId). Every successful execution includes a stable Conto transaction ID.
Check settlementMode before treating the hash or explorer link as evidence of live settlement.Example
payments.pay()
Convenience method that requests and executes in one call.Behavior
- If approved: Executes immediately and returns result
- If denied: Throws
ContoErrorwith codePAYMENT_DENIED - If requires approval: Throws
ContoErrorwith codeREQUIRES_APPROVAL - Other API failures expose the stable
codeandstatusfields from the SDK error contract.
Example
autoExecute Flag
TheautoExecute flag lets payments.request() request authorization and execute the payment in a
single API call.
How It Works
- If APPROVED +
autoExecute: true: Returnsstatus: "EXECUTED"with anexecutionobject containingtransactionId,txHash,explorerUrl, andstatus. - If DENIED or REQUIRES_APPROVAL: Returns the normal authorization response.
Example
payments.status()
Check the status of a payment request.Response
Example: Polling for Confirmation
Status Reference
The status endpoint returns the API’s current status string plus policy and transaction details. When a transaction is present, use itsstatus, txHash, and confirmedAt fields to reconcile the
known request. Do not create a second request while the original request is still unresolved.
Categories
Use standard categories for better analytics:Urgency Levels
Best Practices
Always Include Purpose
Always Include Purpose
Including purpose improves audit trails and analytics:
Handle Expiration
Handle Expiration
Approvals from
/request expire after 5 minutes. Approvals from /approve (external wallets) expire after 10 minutes. Check expiration before executing:Use Two-Step for Complex Flows
Use Two-Step for Complex Flows
Use separate request/execute when you need to:
- Validate before executing
- Show user confirmation
- Handle requires_approval status
Attach Invoice Details
Attach Invoice Details
Use the typed
context.invoice object when a payment is linked to an invoice:Reconciling payments
GET /api/sdk/transactions/reconciliation returns a per-payment reconciliation view: the
requested amount, the settled amount, the settlement hash, the status, and a reconciliation state.
It reads settled transaction data, so finance can tie requested amounts to what actually settled and
export the result.
Filter by
status, from, and to. Pass format=csv for a full server-side export instead of a
paged JSON response.
transactions:read scope.
Next Steps
Error Handling
Handle payment errors gracefully
Examples
See complete integration examples