Payments API
The payments API allows agents to request authorization and execute stablecoin payments.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
| Wallet model | Use this flow | What Conto can stop |
|---|---|---|
Managed (PRIVY, SPONGE) | request -> execute | Conto stays in the execution path and can block the spend |
External (EXTERNAL) | approve -> transfer -> confirm | Conto governs the Conto-routed flow, but cannot block a direct self-signed transfer outside Conto |
payments.request()
Request authorization for a payment. This evaluates policies without executing.Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | number | Yes | Payment amount |
recipientAddress | string | Yes | Wallet address — 0x + 40 hex chars for EVM, or base58 (32-44 chars) for Solana. Validated via Zod schema. |
recipientName | string | No | Human-readable name |
purpose | string | No | Why this payment is needed |
category | string | No | Spending category |
context | object | No | Additional metadata |
walletId | string | No | Specific wallet to use |
urgency | string | No | LOW, NORMAL, HIGH, CRITICAL |
autoExecute | boolean | No | If true, automatically execute the payment when approved. Returns the transaction result directly instead of requiring a separate execute() call. |
targetContractAddress | string | No | Smart contract address for contract interaction policy evaluation |
functionSelector | string | No | 4-byte function selector (e.g., 0xa9059cbb) for contract allowlist rules |
idempotencyKey | string | No | Client-supplied key that makes retries safe. Reusing the same key with the same request returns the original request; reusing it with different request parameters returns a conflict. |
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 preserves that payload in the raw request context and also
stores a typed invoice record on the PaymentRequest. 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.If the policy result is
REQUIRES_APPROVAL and an approval workflow matches, Conto opens the
approval request immediately and includes approvalRequestId in the API response. This is the
handle external verifier systems such as Delta use for callback decisions.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
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
/api/sdk/payments/approve returns requiresHumanApproval: true and a workflow matches, Conto
opens the approval request immediately and includes approvalRequestId in the response. After
that workflow approves the payment, POST /api/sdk/payments/{requestId}/confirm can be called
with just the final txHash; human-approved external payments do not require an approvalToken.Response
All payment responses now include
currency (e.g., “USDC”, “USDT”, “USDC.e”, or “pathUSD”) and
chain (with chainId, chainName, chainType, and explorerUrl) so agents know exactly which network
and token the payment uses.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 originalrequestIdwithidempotent: true - Same
idempotencyKey+ different request payload: returns HTTP409withcode: "IDEMPOTENCY_CONFLICT" - Different
idempotencyKey: creates a new payment request
Example
payments.execute()
Execute an approved payment request.Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
requestId | string | Yes | The requestId from payment request |
Response
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
Example
autoExecute Flag
TheautoExecute flag lets you request authorization and execute the payment in a single API call, without needing a separate execute() call.
How It Works
- If APPROVED +
autoExecute: true: Executes immediately, returnsstatus: "EXECUTED"withexecutionobject containingtxHash - If DENIED or REQUIRES_APPROVAL:
autoExecuteis ignored, normal response returned - If execution fails: Returns
status: "APPROVED"withautoExecuteErrormessage andexecuteUrlfor manual retry
Example
payments.status()
Check the status of a payment request.Response
Example: Polling for Confirmation
Status Reference
Payment requests and transactions use different status values:| Payment Request Status | Description |
|---|---|
APPROVED | Policies passed, ready to execute |
DENIED | Blocked by a policy or wallet limit |
REQUIRES_APPROVAL | Needs manual human approval |
EXECUTED | Auto-executed successfully (when autoExecute: true) |
PENDING | Awaiting human approval (maps to REQUIRES_APPROVAL in SDK response) |
COMPLETED | Payment fully confirmed onchain |
EXPIRED | Approval window elapsed without execution |
| Transaction Status | Description |
|---|---|
PENDING | Transaction submitted, awaiting confirmation |
EXECUTING | Transaction is being processed |
CONFIRMING | Transaction broadcast, awaiting block confirmation |
CONFIRMED | Transaction confirmed onchain |
FAILED | Transaction failed |
REJECTED | Transaction rejected |
CANCELLED | Transaction cancelled before execution |
| Policy Result | Description |
|---|---|
ALLOWED | All policies passed |
DENIED | At least one policy denied the payment |
REQUIRES_APPROVAL | Policies passed but approval threshold triggered |
FLAGGED | Payment flagged for review |
PENDING | Policy evaluation not yet complete |
Categories
Use standard categories for better analytics:| Category | Description |
|---|---|
INFRASTRUCTURE | Cloud, hosting, compute |
AI_SERVICES | AI APIs, model training |
MARKETING | Advertising, promotions |
OPERATIONS | General operations |
VENDOR | Vendor payments |
EMPLOYEE | Employee reimbursements |
TESTING | Test transactions |
Urgency Levels
| Level | Description |
|---|---|
LOW | Can wait, batch if possible |
NORMAL | Standard priority (default) |
HIGH | Process quickly |
CRITICAL | Immediate processing |
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
Add Context for Debugging
Add Context for Debugging
Use the context field for debugging info:
Next Steps
Error Handling
Handle payment errors gracefully
Examples
See complete integration examples