Skip to main content

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.
Payment audit entries snapshot the credential ID, sorted scopes, authentication type, and key type used for the decision. This makes later reviews independent of subsequent key rotation or scope changes.

Credential-gated checkout relay alpha

The default-off checkout relay is a separate hard-control path for supported merchant checkouts. An admin SDK key with merchant:purchase can issue and inspect a five-minute grant at:
  • POST /api/sdk/checkout-relay/grants
  • GET /api/sdk/checkout-relay/grants/{grantId}
Each grant is signed and bound to the agent, card reference, purchase intent, connector, merchant, exact HTTPS origin, USD ceiling, cart hash, policy version, and decision-evidence hash. SDK responses never expose the provider credential reference. Only an authenticated isolated worker can consume a grant once and record its terminal outcome. The alpha is disabled unless the global switch, organization allowlist, merchant allowlist, signing secret, and independent worker secret are all configured. It does not accept or store PAN/CVC.

Overview

The payment flow has two steps:
  1. Request - Request authorization and policy evaluation
  2. Execute - Execute the approved payment onchain
Or use 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

payments.execute() is for managed wallets. If your agent holds the signing keys, use the external-wallet approve -> confirm flow instead.
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.
For production agents, a payment request to an unknown recipient first creates a reviewable DISCOVERED counterparty and agent relationship. The request returns REQUIRES_APPROVAL until an operator advances the counterparty lifecycle. If the review record cannot be persisted, the API fails closed with HTTP 503 and code: "COUNTERPARTY_REVIEW_UNAVAILABLE".
Relationship controls are evaluated after counterparty lifecycle checks. Per-payment, daily, and monthly limits and category restrictions can deny a request. Relationship approval requirements or expired access route the request to review. These controls are specific to the requesting agent and do not replace assigned policies.

External Wallet Approve/Confirm Flow

If your agent holds the signing keys, use the external-wallet flow instead of payments.execute():
  1. Call POST /api/sdk/payments/approve to evaluate policy and receive an approvalToken
  2. Submit the onchain transfer through your own signer or wallet integration
  3. Call POST /api/sdk/payments/{requestId}/confirm with the final txHash, plus the approvalToken when the original /approve response returned one
This keeps the same policy checks and audit trail while leaving execution in the agent’s control. It does not cryptographically block a direct transfer signed outside Conto.
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.
A submitted transaction hash is accepted for asynchronous verification, not treated as final confirmation. The response contains accepted: true, confirmed: false, and status: "processing". Conto marks the transaction confirmed only after verifying the expected chain, sender, recipient, asset, amount, and successful receipt. Poll the returned statusUrl for the final result.
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 with GET /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:
This route requires 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

The 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

Use idempotencyKey when your caller may retry the same payment request because of network timeouts or uncertain client state.
  • Same idempotencyKey + same request payload: returns the original requestId and current next action
  • Same idempotencyKey + different request payload: returns HTTP 409 with code: "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 ContoError with code PAYMENT_DENIED
  • If requires approval: Throws ContoError with code REQUIRES_APPROVAL
  • Other API failures expose the stable code and status fields from the SDK error contract.

Example

autoExecute Flag

The autoExecute flag lets payments.request() request authorization and execute the payment in a single API call.
Requires both payments:request and payments:execute scopes. The standard SDK key preset includes both. If a key lacks payments:execute (for example, a legacy custom-scoped key), the flag is silently ignored and the response is a normal APPROVED status that you must execute separately.

How It Works

  • If APPROVED + autoExecute: true: Returns status: "EXECUTED" with an execution object containing transactionId, txHash, explorerUrl, and status.
  • 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 its status, 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

Including purpose improves audit trails and analytics:
Approvals from /request expire after 5 minutes. Approvals from /approve (external wallets) expire after 10 minutes. Check expiration before executing:
Use separate request/execute when you need to:
  • Validate before executing
  • Show user confirmation
  • Handle requires_approval status
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.
The endpoint uses the transactions:read scope.

Next Steps

Error Handling

Handle payment errors gracefully

Examples

See complete integration examples