Amounts and currencies
Managed payment requests choose currency from the selected wallet’s chain. Use
walletId to bind
that wallet. The request does not accept a chainId or top-level currency override.
External approval requires the sender and chain. Never infer the network from an EVM address alone.
Convert protocol base-unit amounts using the token’s decimals before passing a human-unit amount
to Conto. When recording protocol payments, use the actual settlement currency and total. Batch
item amounts must match the aggregate settlement. Do not send floating-point calculation artifacts
such as 0.30000000000000004 to an endpoint requiring cent precision.
Managed authorization returns APPROVED, DENIED, REQUIRES_APPROVAL, PROCESSING, or
COMPLETED. Replaying a completed request with the same idempotency key returns COMPLETED.
Use the original requestId to check status and reconcile its existing transaction; do not
create a new intent to resume that payment.
Identifiers and addresses
Treat returned IDs as opaque strings. Retain distinct identifiers for:
EVM addresses have
0x followed by 40 hexadecimal characters. Solana uses a base58 public key.
Use the exact address and chain returned by setup. Abbreviated addresses are display values, not
valid request inputs.
Dates and time windows
API timestamps use ISO 8601 strings. Parse them as instants, including the returned timezone. Policy time windows use the configured IANA timezone, which can differ from your browser timezone. Protocol budget summaries use UTC calendar periods. See time windows.Authentication
SendAuthorization: Bearer <key> over HTTPS. Agent calls use CONTO_API_KEY. Organization
provisioning uses CONTO_ORG_API_KEY. Keys are not interchangeable. See
authentication and the scope reference.
Response envelopes and pagination
There is no universalitems envelope. Read the schema of the endpoint you call.
For example, SDK transactions return transactions and counterparties return counterparties.
Both include a nested pagination object:
limit is 50 and maximum is 100 on these endpoints. Advance offset by the number of
records received and stop when hasMore is false. MCP may wrap an API array in
{ "items": [...] } for structured output. This does not change the underlying HTTP endpoint’s
response schema.
Idempotency and retries
Managed authorization acceptsidempotencyKey. Reusing a key with the same payload returns the
same intent. A different payload gives 409 IDEMPOTENCY_CONFLICT. Persist the key across worker
restarts. The SDK generates a key when omitted, but a new method invocation is a new intent unless
you explicitly reuse your saved key.
Execution is not automatically retried. SDK payments.approve() and payments.confirm() also
send each external-wallet write only once. Confirmation records a transfer your signer already
sent. It does not send funds or prove settlement. Retain the approval/request ID and transfer hash
for status reconciliation. External confirmation can return a duplicate conflict.
x402 uses paymentId and MPP uses credentialId for settlement-record identity. These are separate
contracts. Do not assume every write accepts the same idempotency field.
x402 and MPP pre-authorization reserve spend when approved. Retrying with the same paymentId
(x402) or challengeId/credentialId (MPP) returns the same live grant. A retry without one of
those fields issues a second grant and reserves the amount again until the first grant expires.
purchases.create() takes an idempotencyKey and returns the same purchase when the key and
input repeat. purchases.respond() returns the same acknowledgment for the same answer to an
action. The SDK retries both because the server replays them. A purchase never retries a payment
on its own: an uncertain outcome stays in reconciling until the merchant’s confirmation or a
reviewer settles it.
See payment recovery before repeating a write and
SDK error handling for HTTP 402, timeouts, and backoff.
Diagnostic reads and errors
SDKsetup() reads the agent, linked wallets, effective policies, and key scopes without creating
a payment. Use payments.status(requestId) to inspect an existing request. Recognized validation
failures expose fieldErrors with local guidance. Payment errors from payments.pay() and
payments.execute() expose reasons. A declined or held x402 or MPP
pre-authorization returns fixed reasons and reasonCodes. Arbitrary provider diagnostics and
server instructions are not forwarded.
Version compatibility
Record the SDK version used by your application and keep its dependency lockfile. Check the changelog and rerun integration tests when upgrading. Use the OpenAPI document for HTTP contracts and the installed SDK’s types for client methods.Settlement evidence
Payment execute receipts always identify the Conto transaction and settlement mode.txHash and explorerUrl are absent for a simulation (settlementMode: "test"). Status and transaction reads report unknown when execution evidence is missing. live means onchain, including testnet. Neither a completed simulation nor a legacy hash alone proves settlement. See payment lifecycle.
Connected-card writes
Connected cards are available on Builder and Enterprise. A draw’sidempotencyKey identifies one
card credential. Replaying an issued draw returns its status without the one-time secret, and the
SDK does not retry draws automatically. After you receive the credential,
connectedCards.acknowledgeDelivery(requestId) is safe to retry and returns
{ acknowledged: true, settlementVerified: false }. After checkout,
connectedCards.reportOutcome(requestId, { outcome }) is safe to retry with the same report. A
different second report returns 409, and a report never releases held spend by itself.
credentialExpiresAt comes from the card provider and is separate from the approval window. Merchant fields you send must match the
mandate, the verified purchase authorization. Omitted fields default to
the stored merchant.
Stripe Link card references
checkout.confirm() forwards observed lineItems and totals for validation even when
amountMinor is unchanged. A changed cart cannot reuse the original purchase authorization.
Confirmation is idempotent: replaying it returns the existing result and does not authorize a
second payment submission. Keep a durable submission claim in the trusted executor and reconcile
uncertain payment outcomes before sending again.
checkout.getLinkCard() keys one purchase on its idempotencyKey. Retrying with the same input
resumes the same checkpoint and the same Link request, so the person is not asked twice. Keep the
Link request ID (lsrq_...) as the reference for that purchase, and pass it to confirm and outcome
as paymentReference. A checkpoint keeps the first payment reference it receives and returns 409
for a different one. See Stripe Link cards for agents.
Purchase observation
purchases.watch() supports an abort signal and a maxWaitMs observation deadline. Stopping
observation closes its stream without cancelling the purchase. Use purchases.cancel(id) to
request cancellation, and inspect the returned outcome before assuming payment stopped.
See purchase observation for reconnect behavior.