Agent side
Connect an agent
Discover and call resources from an agent over MCP, plain HTTP, A2A or ACP.
Agents need no account and no API key: agent routes are open by design, and paid resources are protected by payment. Start by reading what the gateway offers, then call it over the protocol your agent speaks.
Discover
curl -s https://gateway.example.com/.well-known/agent-commerce
curl -s https://gateway.example.com/api/resourcesCall a resource
npm install @modelcontextprotocol/sdkimport { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const client = new Client({ name: 'my-agent', version: '1.0.0' }, { capabilities: {} });
await client.connect(
new StreamableHTTPClientTransport(new URL('https://gateway.example.com/mcp')),
);
const { tools } = await client.listTools();
// Paid tools state their price in the description and accept `_payment`.
const result = await client.callTool({
name: 'basic_weather',
arguments: { city: 'Berlin' },
});A paid tool called without a proof returns isError: true with the payment envelope in structuredContent. Continue with Handle a payment.
curl -s https://gateway.example.com/api/resources/basic_weather/invoke \
-X POST \
-H 'content-type: application/json' \
-d '{"city":"Berlin"}'The body is the resource input. A successful call returns your backend's status and body; a paid resource without a proof returns 402 with the challenge in the body and the PAYMENT-REQUIRED header.
curl -s https://gateway.example.com/.well-known/agent-card.json
curl -s https://gateway.example.com/a2a \
-H 'content-type: application/json' \
-H 'A2A-Version: 1.0' \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "SendMessage",
"params": {
"message": {
"role": "ROLE_USER",
"messageId": "msg-1",
"parts": [
{ "data": { "resource": "basic_weather", "input": { "city": "Berlin" } } }
]
}
}
}'One message with a messageId and one data part naming the resource and its input. The answer is a terminal task: TASK_STATE_COMPLETED with the merchant response, or TASK_STATE_FAILED carrying the payment or error envelope. With the x402 extension, an unpaid x402 call instead waits in TASK_STATE_INPUT_REQUIRED for payment; see x402 extension.
curl -s https://gateway.example.com/.well-known/acp.json
curl -s https://gateway.example.com/acp/checkout_sessions \
-H "Authorization: Bearer $ACP_BEARER_TOKEN" \
-H "API-Version: 2026-04-17" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"line_items":[{"id":"item_123"}],"currency":"usd","capabilities":{}}'ACP is the one authenticated agent surface: the merchant issues the bearer token. Retry with the same Idempotency-Key and body to get the stored answer back.
Handle errors
Failures use one envelope with a typed code and a retryable flag. Retry only when retryable is true — PAYMENT_PROVIDER_UNAVAILABLE, AUTHORIZATION_PROVIDER_UNAVAILABLE, BACKEND_TIMEOUT and GATEWAY_BUSY. On the HTTP invoke route, the two provider outages answer 503 with Retry-After: 5: no verdict was reached, so the same proof may be sent again after the pause. See Errors.