# Data Dictionary — x402 Client-Compatibility Census (Base + Ethereum, 2026-10-12)

Field-by-field schema for the two distributions of this dataset:

- `dataset.csv` — the flat per-endpoint table (one row per advertised
  endpoint, 280 data rows + header).
- `x402-client-compat-census-2026-10-12.json` — the raw observational
  probe payload (top-level metadata + the same per-endpoint list).

Everything below is captured verbatim from the probe at the probe instant
(`2026-10-12T16:43:01Z`); nothing is synthesised.

## Raw JSON — top-level fields

| Field | Type | Source | Definition |
|---|---|---|---|
| `generated_at_utc` | iso8601 | measured | UTC instant at which every endpoint in `per_endpoint[]` was probed. Same value for all rows. |
| `aggregate` | object | computed | Reduction of `per_endpoint[]`. See `Raw JSON — aggregate{}` below. |
| `per_endpoint` | array | measured | 280-entry list, one entry per advertised endpoint. See per-entry fields below. |

## Raw JSON — `aggregate{}` fields

| Field | Type | Source | Definition |
|---|---|---|---|
| `total_402_endpoints_measured` | int | computed | Count of `per_endpoint[]` rows measured. `280`. |
| `parses_v2_all_accepts` | int | computed | Count of `per_endpoint[]` rows whose body passed the per-entry v2 parser applied to every `accepts[]` entry. `249`. |
| `parses_v2_top_level` | int | computed | Count of `per_endpoint[]` rows whose body passed the full-body v2 discriminated-union parser. `228`. |
| `total_accepts_entries` | int | computed | Sum of `accepts_count` across `per_endpoint[]`. `818`. |
| `v2_accepts_entries_parsed` | int | computed | Count of `accepts[]` entries that parsed under the v2 per-entry parser. `787`. |
| `pct_parses_v2_all_accepts` | float | computed | `100 × parses_v2_all_accepts / total_402_endpoints_measured`. `88.93`. |
| `pct_parses_v2_top_level` | float | computed | `100 × parses_v2_top_level / total_402_endpoints_measured`. `81.43`. |

## Raw JSON — `per_endpoint[]` entry fields

| Field | Type | Source | Definition |
|---|---|---|---|
| `idx` | int | assigned | Zero-based row index in `per_endpoint[]`. Preserved in the CSV so you can line up rows between distributions. |
| `agent_id` | int | measured | ERC-8004 `agentId` on the chain in `chain`. |
| `agent_key` | string | assigned | `chain:agent_id` composite key, unique over the row set. 36 distinct values in this snapshot. |
| `chain` | enum | measured | `base` (chain_id 8453) or `ethereum` (chain_id 1). |
| `url` | url | measured | Advertised endpoint that was probed. |
| `method` | string | measured | HTTP method the agent advertises for this endpoint (always `GET` in this snapshot). |
| `http_status` | nullable int | measured | HTTP status code captured at probe time. `null` (empty cell in the CSV) when no response was received inside the probe timeout window; `402` for well-behaved rows; `503` for the one row where the server returned a service-unavailable. |
| `x402Version` | nullable int | measured | The `x402Version` field read from the response body at probe time. `1`, `2`, or `null` when absent / unparseable. |
| `parses_v2_all_accepts` | bool | measured | `true` when every entry inside the body's `accepts[]` array parses under `@x402/core@2.28.0`'s `PaymentRequirementsSchema`. |
| `parses_v2_top_level` | bool | measured | `true` when the whole body parses under `@x402/core@2.28.0`'s `parsePaymentRequired` discriminated-union parser. |
| `accepts_count` | int | measured | Count of entries in the body's `accepts[]` array at probe time. `0` when the body had no `accepts` field or an empty one. |
| `failure_reasons` | string list | measured | Compact list of named parse-failure modes captured by the probe. Five distinct values observed across the full dataset: `no_accepts_array`, `non_object_body`, `v2_entry_bad_asset`, `v2_top_level:too_small:accepts.12.asset`, and `x402Version_not_1_or_2`. Empty list `[]` on rows that parsed cleanly. |
| `v2_top_level_first_issue` | nullable string | measured | The first Zod issue path captured by the v2 top-level parser when it rejected a body. `null` (empty cell in the CSV) when the body passed or when a non-v2-top-level reason killed the parse earlier. |

## CSV columns (13)

The CSV preserves one row per `per_endpoint[]` entry. One structural
difference from the raw JSON: the `failure_reasons` list is serialised to
a JSON string in `failure_reasons_json` so the CSV stays rectangular.

| # | Column | Type | Null semantics |
|---:|---|---|---|
| 1 | `idx` | int | Always populated (`0..279`). |
| 2 | `agent_id` | int | Always populated. |
| 3 | `agent_key` | string | Always populated. |
| 4 | `chain` | enum | Always populated (`base` or `ethereum`). |
| 5 | `url` | url | Always populated. |
| 6 | `method` | string | Always populated. |
| 7 | `http_status` | int or empty | Empty cell when the source value is `null`. 7 such rows. |
| 8 | `x402Version` | int or empty | Empty cell when the source value is `null`. 17 such rows. |
| 9 | `parses_v2_all_accepts` | bool | Always populated. Serialised as `True`/`False` by python's `csv.writer`. |
| 10 | `parses_v2_top_level` | bool | Always populated. Serialised as `True`/`False`. |
| 11 | `accepts_count` | int | Always populated (zero when the body had no entries). |
| 12 | `failure_reasons_json` | string | Always populated. JSON-encoded array with compact separators (`,` and `:`, no whitespace). Empty array serialises to the two-character literal `[]`. Readers should `json.loads(row['failure_reasons_json'])` to recover the list. |
| 13 | `v2_top_level_first_issue` | string or empty | Empty cell when the source value is `null`. |

Row ordering preserves the source `per_endpoint[]` ordering (`idx` is
sorted ascending); no sort was applied on top of it.

## License

[Creative Commons Attribution 4.0 International (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/).
