Agent Attribution (X-Agent-Info)
Send the optional X-Agent-Info header to attribute agent-driven Trading API traffic, and check x-agent-info-status to confirm it was recognized.
The Uniswap API accepts an optional X-Agent-Info request header. Send it if an AI agent built or operates your integration. It lets us measure agent-driven traffic separately from human-driven traffic.
Optional, and never affects the request
X-Agent-Info is purely for analytics. Humans and human-facing clients can ignore it entirely. Omitting it, sending it, or sending it incorrectly has no effect on your request. It never changes the response status, body, or any swap behavior.
Sending the header
Send X-Agent-Info alongside your usual authentication headers, with a JSON object value containing up to three fields:
| Field | Type | Required | Notes |
|---|---|---|---|
decision_origin | string | Yes | Must be exactly autonomous or human_mediated (case-sensitive). Any other value marks the header malformed. |
integration_name | string | No | Name of your integration or agent, e.g. my-trading-bot. Up to 256 UTF-16 code units, which is JavaScript's String#length. |
version | string | No | Version identifier for your integration. Up to 256 UTF-16 code units. |
Send only these three fields. Any other key is dropped rather than rejected, so an extra key never makes the header malformed.
integration_name and version are stored per request and queried later. Both must be stable strings that describe your software. Never send a user ID, wallet address, email address, session token, API key, or any value derived from an end user. On our side, a malformed header is never echoed back or logged, and only the three fields above ever reach our analytics.
# Fill in your own token addresses and amount. The header is evaluated either way.
curl -X POST https://trade-api.gateway.uniswap.org/v1/quote \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H 'X-Agent-Info: {"decision_origin":"autonomous","integration_name":"my-trading-bot","version":"1.4.0"}' \
-d '{"tokenIn":"0x...","tokenOut":"0x...","tokenInChainId":1,"tokenOutChainId":1,"type":"EXACT_INPUT","amount":"1000000","swapper":"0x...","slippageTolerance":0.5}'What makes a header malformed
A header is dropped (marked malformed) rather than rejected outright if any of the following hold. The request is handled exactly as if the header were absent. See Confirming it was received below for how to tell the difference.
- The raw header value is larger than 1024 bytes, measured on the raw value before parsing. JSON whitespace and
\uescapes count toward the cap. - The raw header value contains any byte outside printable US-ASCII (
0x20–0x7E). This is checked first, before the JSON is parsed, because bytes above0x7Edecode differently in different HTTP stacks. So a literalé, an emoji, or a curly quote in the header marks it malformed no matter how short the value is. Send non-ASCII as a JSON\uescape instead. - The value isn't valid JSON, or is valid JSON that isn't a plain object (an array, string, number, boolean, orÂ
null). - The request carried two or more
X-Agent-Infoheader lines. They are joined with", ", which is almost never valid JSON. Set the header once rather than appending to it, since some HTTP clients append by default. decision_originis missing, or is anything other than exactlyautonomousorÂhuman_mediated.integration_nameorversionis present but isn't a string, or is longer than 256 UTF-16 code units. That count is JavaScript'sString#length, so an emoji or other astral character costs two units, not one.integration_nameorversioncontains a disallowed character. Those are control characters (C00x00–0x1F, DEL0x7F, C10x80–0x9F), the Unicode line separators U+2028 and U+2029, and the replacement character U+FFFD. An escaped unpaired surrogate decodes to U+FFFD, so it is rejected too. Text pasted from a PDF, or left behind by a lossy re-encode, often carries one of these invisibly.
Not sending the header at all isn't an error condition. It's simply "no attribution," the same outcome as a header that's out of scope for your client.
Confirming it was received
Because the request succeeds regardless of whether X-Agent-Info parsed, check the x-agent-info-status response header to confirm your header was actually recognized:
x-agent-info-status: malformed: the header was received but failed one of the checks above and was dropped. The value is always the fixed stringmalformed; it never echoes anything from your request.- No
x-agent-info-statusheader at all: yourX-Agent-Infoheader parsed, or you didn't send one.
The gateway sets this header after it routes your request, and before it writes its own response. Error responses carry it too: a 400, a 401, a 403, a 429, and a 404 for a path that does not exist. So you can debug the header without first getting a working quote. A CORS preflight carries no status header, because the gateway answers it before it looks at X-Agent-Info.
Call the Trading API server-to-server. The gateway sends CORS headers only to a small allow-list of origins, so a browser page on your own domain cannot read this header. Check it from a server or with curl.
const response = await fetch('https://trade-api.gateway.uniswap.org/v1/quote', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
Accept: 'application/json',
'X-Agent-Info': JSON.stringify({
decision_origin: 'autonomous',
integration_name: 'my-trading-bot',
version: '1.4.0',
}),
},
body: JSON.stringify({
tokenIn: '0x...',
tokenOut: '0x...',
tokenInChainId: 1,
tokenOutChainId: 1,
type: 'EXACT_INPUT',
amount: '1000000',
swapper: '0x...',
slippageTolerance: 0.5,
}),
});
if (response.headers.get('x-agent-info-status') === 'malformed') {
// Received but dropped. Check field names, decision_origin value, and length limits above.
console.warn('X-Agent-Info was sent but not recognized.');
}
const quote = await response.json();The only consequence of a malformed header is that your traffic isn't attributed to your integration.