Skip to main content
Every example calls the agent SDK endpoints with the agent’s SDK key as CONTO_API_KEY. Do not use CONTO_ORG_API_KEY for these /api/sdk/* calls. See Keys and scopes.
Before integrating, connect your agent, link a wallet, and generate an SDK key. If you are an autonomous agent evaluating Conto without a human account, try the sandbox first.
The examples use a managed wallet: request, then execute. External wallets use approve, your own transfer, then confirm. See wallet custody.

SDK examples

These use @conto_finance/sdk. See Install the TypeScript SDK.

One-call payment

Use payments.pay() with a managed wallet to request approval and execute in one call. It throws if the payment is denied or needs approval.

Approval-aware payment

Use request() then execute() when your app handles denied or review-required outcomes before execution.

Setup check

Call conto.setup() on agent startup to read the agent, its wallets, spending limits, and scopes.

The shared payment helper

Each framework integration wraps the same two calls: request (policy check), then execute. This helper calls the REST API directly with no SDK dependency. Define it once and call it from each framework’s tool handler. It:
  • Sends the payment to POST /api/sdk/payments/request with an idempotency key, so Conto checks it against your policies.
  • Stops if the result is not APPROVED and returns the status, reasons, and actionUrl. pending is true when the payment waits for approval.
  • Calls POST /api/sdk/payments/{requestId}/execute only for an approved request.
  • Returns the receipt, transaction hash, and explorer URL. success is true only for a completed payment with a transaction ID.
  • Returns uncertain or checkStatus when the outcome is unknown. It never retries.
A processing result means the payment was submitted and awaits confirmation. A sandbox completed result has a test receipt and does not prove an onchain transfer. Keep the request ID and idempotency key with the operation. After a timeout or an uncertain response, check GET /api/sdk/payments/{requestId} before trying again. If the request response was lost, repeat only the authorization request with the same input and idempotency key to recover it. Do not start a new payment. Neither helper retries automatically. The Python equivalent needs pip install requests:

Framework integrations

Each framework needs only its own tool wiring around the shared helper.

OpenAI (Responses API)

Anthropic Claude (tool use)

Python (any framework)

Register make_payment (defined above) as a tool in your framework of choice (CrewAI, AutoGen, or a custom loop) and return its dict result to the model as the tool output.

Server handlers

These handlers take payment requests on your own server. They are examples: add your own application authentication and authorization, and configure the recipient allowlist before you expose a payment route.

Validate before paying

Do not pass an untrusted request body directly to payments.pay(). Put authentication, local limits, a recipient allowlist, and a caller-supplied idempotency key in front of the SDK. Both handlers below use this helper:
  • parsePayment rejects the body unless the amount is positive and at most MAX_PAYMENT_AMOUNT (default 50), the recipient is an EVM address on PAYMENT_RECIPIENT_ALLOWLIST, and the purpose is 1 to 200 characters.
  • submitPayment asks Conto first. A denial returns 403, a payment waiting for approval returns 202, and any other status that is not APPROVED returns 409.
  • It executes only an approved request. After a timeout, a dropped connection, or a 408, 409, 429, or 5xx error, it reads the payment status instead of retrying.
  • mapPaymentError turns SDK errors into HTTP codes: 400 for validation errors, 409 for idempotency conflicts and insufficient balance, 503 for rate limits, and 502 for anything else.
Set PAYMENT_RECIPIENT_ALLOWLIST to comma-separated EVM addresses and MAX_PAYMENT_AMOUNT to your application-level cap.

Express

Connect the helper to an authenticated and authorized Express route. The middleware must verify a user or service identity, enforce your application’s payment-operator permission, and set res.locals.subject. Replace the sample import with your implementation.

Serverless (AWS Lambda)

Put this function behind an API Gateway JWT authorizer and require your application’s own payments:create scope on the route. The handler also checks that scope, rejects requests without a verified subject, validates and caps the body, requires idempotency, and uses the same recipient allowlist and error mapping as the Express route.

Register an agent in an existing organization

If an organization owner has already invited your agent, register it with the owner’s registration token instead of creating a sandbox. A GET request lists the required fields:
Post the token to join the organization and receive a scoped SDK key:
The key has two scopes. With payments:request the agent calls POST /api/sdk/payments/request, which returns a policy decision. With agents:read it reads its own setup with GET /api/sdk/setup and GET /api/sdk/agents/me. Setup includes the agent’s wallet balances, limits, and policy rules even though the key has no wallets:read or policies:read. The key has no payments:execute, payments:approve, or payments:confirm, and it cannot change policies, create keys, or read other agents. An organization owner issues keys with more scopes. See Keys and scopes. Read the agent’s setup with the new key:
externalId is optional but recommended: it makes retries idempotent and gives your system a durable reconciliation key. The registration response confirms the agent status, granted scopes, credential expiration, and the SDK endpoints that credential can call. It shows the SDK key only on the first successful registration. Registering the same externalId again returns the existing agent and credential reference without revealing the key. A retry never changes the key’s scopes. A key registered before agents:read was included has only payments:request. For that key, GET /api/sdk/setup returns 403 with code: "INSUFFICIENT_SCOPE", requiredScope: "agents:read", actor: "owner", and a nextAction. A registration retry returns the same fields in remediation and leaves setup out of endpoints. Conto never adds scopes to an existing key. An organization owner generates a new key for the agent and revokes the old one.

Handle errors

HTTP errors carry a code such as VALIDATION_ERROR, AUTH_FAILED, INSUFFICIENT_SCOPE or RATE_LIMITED. A 5xx or a timeout leaves the outcome unknown, so look up the request status before retrying execution or creating another payment. See error handling for every code. Policy denials are not HTTP errors. /api/sdk/payments/request returns 200 with status: "DENIED" and a reasons array of fixed messages. Rule names and limits appear only in the dashboard.

Next steps

Send a payment

Every payment method and response shape

Track and recover a payment

Check status and recover an uncertain result

Webhooks

Receive approval and payment events

Recipes

Curl snippets for payments, policies, x402, MPP, and monitoring