-
Notifications
You must be signed in to change notification settings - Fork 643
ECO-639: Document the X-Agent-Info attribution header #1144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
63ac4c5
f240420
5a5f4ea
cba1447
7723048
8ff8ffa
c424534
e696e0c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| --- | ||
| title: Agent Attribution (X-Agent-Info) | ||
| description: 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. | ||
|
|
||
| <Callout title="Optional, and never affects the request" type="info"> | ||
|
|
||
| `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. | ||
|
|
||
| </Callout> | ||
|
|
||
| ## Sending the header | ||
|
|
||
| Send `X-Agent-Info` alongside your usual [authentication](/docs/trading/swapping-api/integration-guide#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 — 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. | ||
|
|
||
| ```bash | ||
| # 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 '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](#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 `\u` escapes 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 above `0x7E` decode 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 `\u` escape 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-Info` header lines. They are joined with `", "`, which is almost never valid JSON. Set the header once rather than appending to it — some HTTP clients append by default. | ||
| - `decision_origin` is missing, or is anything other than exactly `autonomous` or `human_mediated`. | ||
| - `integration_name` or `version` is present but isn't a string, or is longer than 256 UTF-16 code units. That count is JavaScript's `String#length`, so an emoji or other astral character costs two units, not one. | ||
| - `integration_name` or `version` contains a disallowed character. Those are control characters (C0 `0x00`–`0x1F`, DEL `0x7F`, C1 `0x80`–`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, or sending it with an empty value, isn't an error condition — both are 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: | ||
|
Comment on lines
+47
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per the PR description, some of these parse rules ("Several parse rules are also missing or stated in the wrong unit") may not match the shipped parser ( |
||
|
|
||
| - **`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 string `malformed`; it never echoes anything from your request. | ||
| - **No `x-agent-info-status` header at all** — your `X-Agent-Info` header 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. | ||
|
|
||
| ```typescript | ||
| 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', | ||
| '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(); | ||
| ``` | ||
|
wkoutre marked this conversation as resolved.
Comment on lines
+57
to
+92
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This entire section describes an |
||
|
|
||
| The only consequence of a malformed header is that your traffic isn't attributed to your integration. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,8 @@ description: Troubleshoot common Uniswap API request, quoting, authentication, a | |
|
|
||
| The API is specific about request header validation. In particular, ensure that your `accept` and `content-type` headers only include the value `application/json`. For a complete example of properly formatted request headers, see the authentication section of the [Developer Dashboard](https://developers.uniswap.org/dashboard). | ||
|
|
||
| If you're sending the optional `X-Agent-Info` attribution header and it isn't being picked up, check the response for an `x-agent-info-status: malformed` header — see [Agent Attribution](/docs/trading/swapping-api/agent-attribution#confirming-it-was-received) for the full set of rules that make the header malformed. A malformed `X-Agent-Info` never causes an error response; the request proceeds without attribution. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This also references the |
||
|
|
||
| ### Rate limits | ||
|
|
||
| Most API keys have a default rate limit of 6 requests per second (RPS). If you exceed the rate limit supported by an API key you can expect to receive an HTTP 429 error. If you receive a 429 error, we recommend pausing all requests from your API key and then retrying your requests. If you require a higher rate limit than what your API key is currently provisioned for, please reach out to [Uniswap Developer Support](https://support.uniswap.org/hc/en-us/requests/new). For more information on rate limits, see the [Developer Dashboard](https://developers.uniswap.org/dashboard). | ||
|
|
@@ -25,7 +27,7 @@ The most commonly encountered HTTP error is an HTTP 404 with a message "No quote | |
|
|
||
| ### 400 Request validation error | ||
|
|
||
| Request validation errors are returned when a request does not contain the minimum required set of fields or has other syntactical errors. Some examples are a required field (ex. `autoSlippage` in the [`/quote`](/docs/trading/swapping-api/getting-started) endpoint) is not populated, or an address is missing a character (eg. is 39 characters long instead of 40). These errors typically include a specific error message which describes the field which could not be interpreted. | ||
| Request validation errors are returned when a request does not contain the minimum required set of fields or has other syntactical errors. Some examples are a required field is not populated ([`/quote`](/docs/trading/swapping-api/getting-started) requires `type`, `amount`, `tokenInChainId`, `tokenOutChainId`, `tokenIn`, `tokenOut`, and `swapper`), or an address is missing a character (eg. is 39 characters long instead of 40). These errors typically include a specific error message which describes the field which could not be interpreted. | ||
|
|
||
| ### 401 Unauthorized error | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Frontmatter claims a response header that doesn't appear to exist. This
description(and the "Confirming it was received" section below) documents anx-agent-info-statusresponse header. Per the PR's own description, this header shipped inUniswap/backend#11003, which was closed unmerged and superseded by#11941(gateway parser only) — agit grep x-agent-info-statuson backendmainreportedly returns nothing. If that's accurate, this page documents a feature that was never shipped. Please confirm against the current backend implementation before merging (the PR author flagged this as "not ready to merge" for this exact reason).