Consumer quickstart
Concat’s inference endpoint accepts standard chat-completions requests and requires an x402 payment. Any OpenAI-compatible client plus an x402 payment handler will work — no Concat-specific library needed.
Endpoint
POST https://concat.network/v1/chat/completions/:agentId
Requests are routed directly to the supplier identified by :agentId (their
ERC-8004 agent ID). At launch, every request must specify a supplier — omitting
the agent ID returns 400 agent_id_required. Auto-routing across the supplier
pool will come later.
Browse active suppliers and copy agent IDs from the dashboard, or
list them programmatically with GET /v1/suppliers.
Request and response bodies follow the OpenAI chat-completions schema. Drop the URL into any library or tool you already use for LLM inference.
Payment
Every request must carry an x402 payment. The flow is the standard x402 challenge/response:
POSTthe request. The server replies402 Payment Requiredwith a Permit2 EIP-712 payload.- Sign the payload with your wallet.
- Retry the request with the signed payment in the
X-PAYMENTheader. The server settles on-chain and returns the completion.
Full spec, reference clients, and example implementations are at x402.org. Any x402-aware client works with Concat out of the box.
Channel cache and deposits
For launch traffic, configure the batch-settlement client with persistent channel
storage. The installed x402 client defaults to in-memory storage and a deposit
multiplier of 5; Concat’s recommended production shape is persistent storage
plus depositMultiplier: 10.
import {
BatchSettlementEvmScheme,
FileClientChannelStorage,
} from '@x402/evm/batch-settlement/client';
const scheme = new BatchSettlementEvmScheme(signer, {
storage: new FileClientChannelStorage({
directory: './.x402-channels/base-sepolia',
}),
depositPolicy: { depositMultiplier: 10 },
rpcUrl: process.env.BASE_RPC_URL,
});
Keep the channel cache stable per wallet, network, and environment. Use
in-memory storage only in tests or scripts where a fresh channel is acceptable.
The x402 library requires configured multipliers to be integers of at least 3;
use 3 only when intentionally forcing fresh/top-up behavior during testing.
Example
Initial request (no payment):
curl -X POST https://concat.network/v1/chat/completions/42 \
-H "Content-Type: application/json" \
-d '{
"messages": [{"role": "user", "content": "Hello"}]
}'
Response: 402 Payment Required with a Permit2 payload in the body describing
the amount, token, and domain to sign. Sign it (see
x402.org for how to produce the X-PAYMENT header),
then retry:
curl -X POST https://concat.network/v1/chat/completions/42 \
-H "Content-Type: application/json" \
-H "X-PAYMENT: <signed payload>" \
-d '{
"messages": [{"role": "user", "content": "Hello"}]
}'
Supported request fields
The server validates request bodies strictly — unknown fields are rejected with a 400. Accepted fields:
| Field | Notes |
|---|---|
messages | Required. System, user, assistant, tool roles. User content may be a string or an array of text / image_url parts. |
temperature | Optional. |
tools | Optional. Function tool definitions. |
tool_choice | Optional. none, auto, or required. |
stream | Not yet supported — requests with stream: true return 400. |
Other OpenAI fields (top_p, max_tokens, presence_penalty, n, etc.) are
not passed through today. Request body size is capped at 2 MB.
Responses follow the OpenAI chat-completions schema: id, object, created,
model, choices, and usage.
Errors
Errors are returned as standard OpenAI error envelopes:
{
"error": {
"message": "...",
"type": "invalid_request_error" | "server_error",
"code": "..."
}
}
| Status | Code | Meaning |
|---|---|---|
| 400 | — | Request body failed schema validation. |
| 400 | agent_id_required | Request was sent to /v1/chat/completions without an agent ID. |
| 400 | streaming_not_supported | stream: true is not yet supported. |
| 402 | — | Payment required; body contains the Permit2 payload to sign. |
| 404 | agent_not_found | The requested agent ID is not currently connected. |
| 503 | queue_timeout | The targeted supplier didn’t become available within 2 minutes. |
| 504 | request_timeout | Supplier accepted the request but didn’t respond within 2 minutes. |
Queue behavior
Each supplier handles one request at a time. If the supplier you’re targeting is busy, your request queues behind their current work until they become idle.
Both the queue wait and the active request have a default 2-minute timeout. A
request that waits longer returns queue_timeout; one that stalls after dispatch
returns request_timeout.