BinderDex API
Batch prices
Proposed POST /v1/prices/batch
POST/v1/prices/batch
Requires prices:read. Submit one explicit selection per requested lane. Card selections require both variant and condition; sealed selections have no implicit variant or condition. Exact duplicate selections are a whole-request 400 even if JSON property order differs. Same product with distinct selections is allowed. Input order is preserved.
Proposed access: send an X-API-Key header from a server-side integration. Keys are unavailable during preview.
Response shape
| Field | Type | Required | Description |
|---|---|---|---|
data | array<PriceResult> | Yes | minItems: 1 · maxItems: 50 |
data[].selection | PriceSelection | Yes | A requested price lane. Selection kind must match the verified product kind. |
data[].selection (option 1).kind | string | Yes | "card" const: card |
data[].selection (option 1).product_id | string | Yes | Opaque immutable BinderDex public product ID. Never parse it; slugs and upstream IDs are aliases, not identity. Demo IDs and mappings are synthetic. pattern: ^bdp_[a-z0-9_]{3,64}$ |
data[].selection (option 1).variant | string | Yes | minLength: 1 · maxLength: 100 |
data[].selection (option 1).condition | string | Yes | ["near_mint","lightly_played","moderately_played","heavily_played","damaged","ungraded"] enum: ["near_mint","lightly_played","moderately_played","heavily_played","damaged","ungraded"] |
data[].selection (option 2).kind | string | Yes | "sealed" const: sealed |
data[].selection (option 2).product_id | string | Yes | Opaque immutable BinderDex public product ID. Never parse it; slugs and upstream IDs are aliases, not identity. Demo IDs and mappings are synthetic. pattern: ^bdp_[a-z0-9_]{3,64}$ |
data[].status | string | Yes | ["fresh","stale","unknown","missing"] enum: ["fresh","stale","unknown","missing"] |
data[].price | Money | null | Yes | — |
data[].price (option 1).amount_cents | integer | Yes | minimum: 0 · maximum: 9007199254740991 |
data[].price (option 1).currency | string | Yes | "USD" const: USD |
data[].observation | Observation | null | Yes | — |
data[].observation (option 1).source | string | Yes | "licensed_reference" const: licensed_reference |
data[].observation (option 1).source_as_of | string | null | Yes | format: date-time · pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$ |
data[].observation (option 1).collected_at | string | Yes | format: date-time · pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$ |
data[].observation (option 1).basis | string | Yes | "market_reference" const: market_reference |
data[].observation (option 1).attribution | string | Yes | — |
data[].missing_reason | string | null | Yes | ["not_found","no_observation","not_licensed","unsupported_selection",null] enum: ["not_found","no_observation","not_licensed","unsupported_selection",null] |
meta | Meta | Yes | Freshness is evaluated at snapshot_at, which stays original on a batch replay. Other metadata is generated per response. Proposed commercial semantics: successful data calls may consume one request unit, including empty or missing data; replays and errors consume zero. additionalProperties: false |
meta.request_id | string | Yes | pattern: ^req_[a-zA-Z0-9_-]+$ |
meta.snapshot_at | string | Yes | format: date-time · pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$ |
meta.billable_units | integer | Yes | [0,1] enum: [0,1] |
meta.idempotent_replay | boolean | Yes | — |
Response headers
| Header | Type | Preview meaning |
|---|---|---|
X-Request-Id | string | Request correlation identifier; safe to send to support. |
X-Request-Credits-Remaining | integer | Organization credits remaining after this request. Present only after successful key authentication. |
X-Request-Credits-Charged | integer | 0 or 1 for this response; internal cache hits count, idempotent batch replays do not. |
Cache-Control | string | private, no-store; key-specific metadata must never enter a shared HTTP cache. Server-side data caching is separate. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | Yes | Required. Organization+operation-scoped, body-bound key retained 10 minutes. Same normalized body within retention returns original data/snapshot, charged 0 even at quota exhaustion (still rate limited and reauthorized). Different body returns 409. After retention a key is a new request; use a new key for each nightly job. Failed requests are not retained. pattern: ^[A-Za-z0-9_-]{1,64}$ |
Request body
One to fifty explicit selections. No variant or condition defaults are inferred for raw cards.
| Field | Type | Required | Description |
|---|---|---|---|
items | array<PriceSelection> | Yes | Exact duplicate selections are invalid even if JSON property order differs. The same product with a different explicit variant or condition is allowed. minItems: 1 · maxItems: 50 · uniqueItems: true |
items[] (option 1).kind | string | Yes | "card" const: card |
items[] (option 1).product_id | string | Yes | Opaque immutable BinderDex public product ID. Never parse it; slugs and upstream IDs are aliases, not identity. Demo IDs and mappings are synthetic. pattern: ^bdp_[a-z0-9_]{3,64}$ |
items[] (option 1).variant | string | Yes | minLength: 1 · maxLength: 100 |
items[] (option 1).condition | string | Yes | ["near_mint","lightly_played","moderately_played","heavily_played","damaged","ungraded"] enum: ["near_mint","lightly_played","moderately_played","heavily_played","damaged","ungraded"] |
items[] (option 2).kind | string | Yes | "sealed" const: sealed |
items[] (option 2).product_id | string | Yes | Opaque immutable BinderDex public product ID. Never parse it; slugs and upstream IDs are aliases, not identity. Demo IDs and mappings are synthetic. pattern: ^bdp_[a-z0-9_]{3,64}$ |
{
"items": [
{
"kind": "card",
"product_id": "bdp_demo_pikachu_en",
"variant": "normal",
"condition": "near_mint"
},
{
"kind": "card",
"product_id": "bdp_demo_luffy_en",
"variant": "foil",
"condition": "near_mint"
},
{
"kind": "sealed",
"product_id": "bdp_demo_151_bundle_en"
}
]
}Synthetic example
{
"data": [
{
"selection": {
"kind": "card",
"product_id": "bdp_demo_pikachu_en",
"variant": "normal",
"condition": "near_mint"
},
"status": "fresh",
"price": {
"amount_cents": 1250,
"currency": "USD"
},
"observation": {
"source": "licensed_reference",
"source_as_of": "2026-09-06T10:00:00Z",
"collected_at": "2026-09-06T11:00:00Z",
"basis": "market_reference",
"attribution": "Synthetic preview observation — no provider data."
},
"missing_reason": null
},
{
"selection": {
"kind": "card",
"product_id": "bdp_demo_luffy_en",
"variant": "foil",
"condition": "near_mint"
},
"status": "stale",
"price": {
"amount_cents": 2080,
"currency": "USD"
},
"observation": {
"source": "licensed_reference",
"source_as_of": "2026-09-04T00:00:00Z",
"collected_at": "2026-09-04T01:00:00Z",
"basis": "market_reference",
"attribution": "Synthetic preview observation — no provider data."
},
"missing_reason": null
},
{
"selection": {
"kind": "sealed",
"product_id": "bdp_demo_151_bundle_en"
},
"status": "missing",
"price": null,
"observation": null,
"missing_reason": "no_observation"
}
],
"meta": {
"request_id": "req_example",
"snapshot_at": "2026-09-06T12:00:00Z",
"billable_units": 1,
"idempotent_replay": false
}
}Nested definitions
These are the exact reusable shapes referenced by this operation. Constraints are derived from the preview contract.
BatchRequestSchema definition
| Field | Type | Required | Description |
|---|---|---|---|
items | array<PriceSelection> | Yes | Exact duplicate selections are invalid even if JSON property order differs. The same product with a different explicit variant or condition is allowed. minItems: 1 · maxItems: 50 · uniqueItems: true |
items[] (option 1).kind | string | Yes | "card" const: card |
items[] (option 1).product_id | string | Yes | Opaque immutable BinderDex public product ID. Never parse it; slugs and upstream IDs are aliases, not identity. Demo IDs and mappings are synthetic. pattern: ^bdp_[a-z0-9_]{3,64}$ |
items[] (option 1).variant | string | Yes | minLength: 1 · maxLength: 100 |
items[] (option 1).condition | string | Yes | ["near_mint","lightly_played","moderately_played","heavily_played","damaged","ungraded"] enum: ["near_mint","lightly_played","moderately_played","heavily_played","damaged","ungraded"] |
items[] (option 2).kind | string | Yes | "sealed" const: sealed |
items[] (option 2).product_id | string | Yes | Opaque immutable BinderDex public product ID. Never parse it; slugs and upstream IDs are aliases, not identity. Demo IDs and mappings are synthetic. pattern: ^bdp_[a-z0-9_]{3,64}$ |
Full canonical schema JSON
{
"type": "object",
"properties": {
"items": {
"type": "array",
"minItems": 1,
"maxItems": 50,
"uniqueItems": true,
"items": {
"$ref": "#/components/schemas/PriceSelection"
},
"description": "Exact duplicate selections are invalid even if JSON property order differs. The same product with a different explicit variant or condition is allowed."
}
},
"required": [
"items"
],
"additionalProperties": false
}BatchResponseOne result per requested selection in input order. Unknown IDs are per-item missing/not_found. Kind mismatches and unsupported verified raw-card lanes are per-item missing/unsupported_selection. Exact duplicate selections are a whole-request 400.
| Field | Type | Required | Description |
|---|---|---|---|
data | array<PriceResult> | Yes | minItems: 1 · maxItems: 50 |
data[].selection | PriceSelection | Yes | A requested price lane. Selection kind must match the verified product kind. |
data[].selection (option 1).kind | string | Yes | "card" const: card |
data[].selection (option 1).product_id | string | Yes | Opaque immutable BinderDex public product ID. Never parse it; slugs and upstream IDs are aliases, not identity. Demo IDs and mappings are synthetic. pattern: ^bdp_[a-z0-9_]{3,64}$ |
data[].selection (option 1).variant | string | Yes | minLength: 1 · maxLength: 100 |
data[].selection (option 1).condition | string | Yes | ["near_mint","lightly_played","moderately_played","heavily_played","damaged","ungraded"] enum: ["near_mint","lightly_played","moderately_played","heavily_played","damaged","ungraded"] |
data[].selection (option 2).kind | string | Yes | "sealed" const: sealed |
data[].selection (option 2).product_id | string | Yes | Opaque immutable BinderDex public product ID. Never parse it; slugs and upstream IDs are aliases, not identity. Demo IDs and mappings are synthetic. pattern: ^bdp_[a-z0-9_]{3,64}$ |
data[].status | string | Yes | ["fresh","stale","unknown","missing"] enum: ["fresh","stale","unknown","missing"] |
data[].price | Money | null | Yes | — |
data[].price (option 1).amount_cents | integer | Yes | minimum: 0 · maximum: 9007199254740991 |
data[].price (option 1).currency | string | Yes | "USD" const: USD |
data[].observation | Observation | null | Yes | — |
data[].observation (option 1).source | string | Yes | "licensed_reference" const: licensed_reference |
data[].observation (option 1).source_as_of | string | null | Yes | format: date-time · pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$ |
data[].observation (option 1).collected_at | string | Yes | format: date-time · pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$ |
data[].observation (option 1).basis | string | Yes | "market_reference" const: market_reference |
data[].observation (option 1).attribution | string | Yes | — |
data[].missing_reason | string | null | Yes | ["not_found","no_observation","not_licensed","unsupported_selection",null] enum: ["not_found","no_observation","not_licensed","unsupported_selection",null] |
meta | Meta | Yes | Freshness is evaluated at snapshot_at, which stays original on a batch replay. Other metadata is generated per response. Proposed commercial semantics: successful data calls may consume one request unit, including empty or missing data; replays and errors consume zero. additionalProperties: false |
meta.request_id | string | Yes | pattern: ^req_[a-zA-Z0-9_-]+$ |
meta.snapshot_at | string | Yes | format: date-time · pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$ |
meta.billable_units | integer | Yes | [0,1] enum: [0,1] |
meta.idempotent_replay | boolean | Yes | — |
Full canonical schema JSON
{
"type": "object",
"properties": {
"data": {
"type": "array",
"minItems": 1,
"maxItems": 50,
"items": {
"$ref": "#/components/schemas/PriceResult"
}
},
"meta": {
"$ref": "#/components/schemas/Meta"
}
},
"required": [
"data",
"meta"
],
"additionalProperties": false,
"description": "One result per requested selection in input order. Unknown IDs are per-item missing/not_found. Kind mismatches and unsupported verified raw-card lanes are per-item missing/unsupported_selection. Exact duplicate selections are a whole-request 400."
}PriceSelectionA requested price lane. Selection kind must match the verified product kind.
| Field | Type | Required | Description |
|---|---|---|---|
option 1.kind | string | Yes | "card" const: card |
option 1.product_id | string | Yes | Opaque immutable BinderDex public product ID. Never parse it; slugs and upstream IDs are aliases, not identity. Demo IDs and mappings are synthetic. pattern: ^bdp_[a-z0-9_]{3,64}$ |
option 1.variant | string | Yes | minLength: 1 · maxLength: 100 |
option 1.condition | string | Yes | ["near_mint","lightly_played","moderately_played","heavily_played","damaged","ungraded"] enum: ["near_mint","lightly_played","moderately_played","heavily_played","damaged","ungraded"] |
option 2.kind | string | Yes | "sealed" const: sealed |
option 2.product_id | string | Yes | Opaque immutable BinderDex public product ID. Never parse it; slugs and upstream IDs are aliases, not identity. Demo IDs and mappings are synthetic. pattern: ^bdp_[a-z0-9_]{3,64}$ |
Full canonical schema JSON
{
"oneOf": [
{
"$ref": "#/components/schemas/CardPriceSelection"
},
{
"$ref": "#/components/schemas/SealedPriceSelection"
}
],
"discriminator": {
"propertyName": "kind",
"mapping": {
"card": "#/components/schemas/CardPriceSelection",
"sealed": "#/components/schemas/SealedPriceSelection"
}
},
"description": "A requested price lane. Selection kind must match the verified product kind."
}CardPriceSelectionExplicit raw-card price lane. Ungraded is distinct from near_mint and is never converted.
| Field | Type | Required | Description |
|---|---|---|---|
kind | string | Yes | "card" const: card |
product_id | string | Yes | Opaque immutable BinderDex public product ID. Never parse it; slugs and upstream IDs are aliases, not identity. Demo IDs and mappings are synthetic. pattern: ^bdp_[a-z0-9_]{3,64}$ |
variant | string | Yes | minLength: 1 · maxLength: 100 |
condition | string | Yes | ["near_mint","lightly_played","moderately_played","heavily_played","damaged","ungraded"] enum: ["near_mint","lightly_played","moderately_played","heavily_played","damaged","ungraded"] |
Full canonical schema JSON
{
"type": "object",
"properties": {
"kind": {
"type": "string",
"const": "card"
},
"product_id": {
"type": "string",
"pattern": "^bdp_[a-z0-9_]{3,64}$",
"description": "Opaque immutable BinderDex public product ID. Never parse it; slugs and upstream IDs are aliases, not identity. Demo IDs and mappings are synthetic."
},
"variant": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"condition": {
"type": "string",
"enum": [
"near_mint",
"lightly_played",
"moderately_played",
"heavily_played",
"damaged",
"ungraded"
]
}
},
"required": [
"kind",
"product_id",
"variant",
"condition"
],
"additionalProperties": false,
"description": "Explicit raw-card price lane. Ungraded is distinct from near_mint and is never converted."
}SealedPriceSelectionExplicit sealed-product selection. No raw-card variant or condition applies.
| Field | Type | Required | Description |
|---|---|---|---|
kind | string | Yes | "sealed" const: sealed |
product_id | string | Yes | Opaque immutable BinderDex public product ID. Never parse it; slugs and upstream IDs are aliases, not identity. Demo IDs and mappings are synthetic. pattern: ^bdp_[a-z0-9_]{3,64}$ |
Full canonical schema JSON
{
"type": "object",
"properties": {
"kind": {
"type": "string",
"const": "sealed"
},
"product_id": {
"type": "string",
"pattern": "^bdp_[a-z0-9_]{3,64}$",
"description": "Opaque immutable BinderDex public product ID. Never parse it; slugs and upstream IDs are aliases, not identity. Demo IDs and mappings are synthetic."
}
},
"required": [
"kind",
"product_id"
],
"additionalProperties": false,
"description": "Explicit sealed-product selection. No raw-card variant or condition applies."
}PriceResultOne result per selection in input order. fresh: source_as_of <=36h old at snapshot_at; stale: >36h; unknown: price exists but source_as_of is null; missing: no distributable price. A kind mismatch or unsupported verified variant/condition lane is per-item missing/unsupported_selection; unknown ID is per-item missing/not_found. No synthetic fills or provider blending.
| Field | Type | Required | Description |
|---|---|---|---|
selection | PriceSelection | Yes | A requested price lane. Selection kind must match the verified product kind. |
selection (option 1).kind | string | Yes | "card" const: card |
selection (option 1).product_id | string | Yes | Opaque immutable BinderDex public product ID. Never parse it; slugs and upstream IDs are aliases, not identity. Demo IDs and mappings are synthetic. pattern: ^bdp_[a-z0-9_]{3,64}$ |
selection (option 1).variant | string | Yes | minLength: 1 · maxLength: 100 |
selection (option 1).condition | string | Yes | ["near_mint","lightly_played","moderately_played","heavily_played","damaged","ungraded"] enum: ["near_mint","lightly_played","moderately_played","heavily_played","damaged","ungraded"] |
selection (option 2).kind | string | Yes | "sealed" const: sealed |
selection (option 2).product_id | string | Yes | Opaque immutable BinderDex public product ID. Never parse it; slugs and upstream IDs are aliases, not identity. Demo IDs and mappings are synthetic. pattern: ^bdp_[a-z0-9_]{3,64}$ |
status | string | Yes | ["fresh","stale","unknown","missing"] enum: ["fresh","stale","unknown","missing"] |
price | Money | null | Yes | — |
price (option 1).amount_cents | integer | Yes | minimum: 0 · maximum: 9007199254740991 |
price (option 1).currency | string | Yes | "USD" const: USD |
observation | Observation | null | Yes | — |
observation (option 1).source | string | Yes | "licensed_reference" const: licensed_reference |
observation (option 1).source_as_of | string | null | Yes | format: date-time · pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$ |
observation (option 1).collected_at | string | Yes | format: date-time · pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$ |
observation (option 1).basis | string | Yes | "market_reference" const: market_reference |
observation (option 1).attribution | string | Yes | — |
missing_reason | string | null | Yes | ["not_found","no_observation","not_licensed","unsupported_selection",null] enum: ["not_found","no_observation","not_licensed","unsupported_selection",null] |
Full canonical schema JSON
{
"type": "object",
"properties": {
"selection": {
"$ref": "#/components/schemas/PriceSelection"
},
"status": {
"type": "string",
"enum": [
"fresh",
"stale",
"unknown",
"missing"
]
},
"price": {
"oneOf": [
{
"$ref": "#/components/schemas/Money"
},
{
"type": "null"
}
]
},
"observation": {
"oneOf": [
{
"$ref": "#/components/schemas/Observation"
},
{
"type": "null"
}
]
},
"missing_reason": {
"type": [
"string",
"null"
],
"enum": [
"not_found",
"no_observation",
"not_licensed",
"unsupported_selection",
null
]
}
},
"required": [
"selection",
"status",
"price",
"observation",
"missing_reason"
],
"additionalProperties": false,
"description": "One result per selection in input order. fresh: source_as_of <=36h old at snapshot_at; stale: >36h; unknown: price exists but source_as_of is null; missing: no distributable price. A kind mismatch or unsupported verified variant/condition lane is per-item missing/unsupported_selection; unknown ID is per-item missing/not_found. No synthetic fills or provider blending.",
"allOf": [
{
"if": {
"properties": {
"status": {
"const": "missing"
}
}
},
"then": {
"properties": {
"price": {
"type": "null"
},
"observation": {
"type": "null"
},
"missing_reason": {
"type": "string",
"enum": [
"not_found",
"no_observation",
"not_licensed",
"unsupported_selection"
]
}
}
},
"else": {
"properties": {
"price": {
"$ref": "#/components/schemas/Money"
},
"observation": {
"$ref": "#/components/schemas/Observation"
},
"missing_reason": {
"type": "null"
}
}
}
},
{
"if": {
"properties": {
"status": {
"const": "unknown"
}
}
},
"then": {
"properties": {
"observation": {
"properties": {
"source_as_of": {
"type": "null"
}
}
}
}
}
},
{
"if": {
"properties": {
"status": {
"enum": [
"fresh",
"stale"
]
}
}
},
"then": {
"properties": {
"observation": {
"properties": {
"source_as_of": {
"type": "string",
"format": "date-time",
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,3})?Z$"
}
}
}
}
}
}
]
}MoneyInteger US cents. No foreign-exchange conversion; null price means unknown, never zero. Zero is a valid observed amount.
| Field | Type | Required | Description |
|---|---|---|---|
amount_cents | integer | Yes | minimum: 0 · maximum: 9007199254740991 |
currency | string | Yes | "USD" const: USD |
Full canonical schema JSON
{
"type": "object",
"properties": {
"amount_cents": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"currency": {
"type": "string",
"const": "USD"
}
},
"required": [
"amount_cents",
"currency"
],
"additionalProperties": false,
"description": "Integer US cents. No foreign-exchange conversion; null price means unknown, never zero. Zero is a valid observed amount."
}ObservationSource label and attribution must be contractually permitted. source_as_of is the provider observation time, never import time. Mock observations are wholly synthetic. Freshness unknown when source_as_of is absent even if collection time is recent. collected_at is required when an observation exists. Temporal invariant: source_as_of (when known) <= collected_at <= meta.snapshot_at; quarantine invalid upstream records. licensed_reference is a synthetic placeholder; finalize the stable licensed source identifier and attribution before public v1.
| Field | Type | Required | Description |
|---|---|---|---|
source | string | Yes | "licensed_reference" const: licensed_reference |
source_as_of | string | null | Yes | format: date-time · pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$ |
collected_at | string | Yes | format: date-time · pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$ |
basis | string | Yes | "market_reference" const: market_reference |
attribution | string | Yes | — |
Full canonical schema JSON
{
"type": "object",
"properties": {
"source": {
"type": "string",
"const": "licensed_reference"
},
"source_as_of": {
"type": [
"string",
"null"
],
"format": "date-time",
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,3})?Z$"
},
"collected_at": {
"type": "string",
"format": "date-time",
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,3})?Z$"
},
"basis": {
"type": "string",
"const": "market_reference"
},
"attribution": {
"type": "string"
}
},
"required": [
"source",
"source_as_of",
"collected_at",
"basis",
"attribution"
],
"additionalProperties": false,
"description": "Source label and attribution must be contractually permitted. source_as_of is the provider observation time, never import time. Mock observations are wholly synthetic. Freshness unknown when source_as_of is absent even if collection time is recent. collected_at is required when an observation exists. Temporal invariant: source_as_of (when known) <= collected_at <= meta.snapshot_at; quarantine invalid upstream records. licensed_reference is a synthetic placeholder; finalize the stable licensed source identifier and attribution before public v1."
}MetaFreshness is evaluated at snapshot_at, which stays original on a batch replay. Other metadata is generated per response. Proposed commercial semantics: successful data calls may consume one request unit, including empty or missing data; replays and errors consume zero.
| Field | Type | Required | Description |
|---|---|---|---|
request_id | string | Yes | pattern: ^req_[a-zA-Z0-9_-]+$ |
snapshot_at | string | Yes | format: date-time · pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$ |
billable_units | integer | Yes | [0,1] enum: [0,1] |
idempotent_replay | boolean | Yes | — |
Full canonical schema JSON
{
"type": "object",
"properties": {
"request_id": {
"type": "string",
"pattern": "^req_[a-zA-Z0-9_-]+$"
},
"snapshot_at": {
"type": "string",
"format": "date-time",
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,3})?Z$"
},
"billable_units": {
"type": "integer",
"enum": [
0,
1
]
},
"idempotent_replay": {
"type": "boolean"
}
},
"required": [
"request_id",
"snapshot_at",
"billable_units",
"idempotent_replay"
],
"additionalProperties": false,
"description": "Freshness is evaluated at snapshot_at, which stays original on a batch replay. Other metadata is generated per response. Proposed commercial semantics: successful data calls may consume one request unit, including empty or missing data; replays and errors consume zero."
}ErrorNo secrets, SQL, or stack traces. retry_after_seconds is non-null for 429/503 and matches Retry-After. Retry rate/503 with bounded backoff and jitter; quota retry waits until period_end or explicit upgrade. 401/403/400/409 are not blind-retryable.
| Field | Type | Required | Description |
|---|---|---|---|
error | object | Yes | additionalProperties: false |
error.code | string | Yes | ["invalid_request","invalid_api_key","insufficient_scope","not_found","idempotency_conflict","payload_too_large","unsupported_media_type","rate_limit_exceeded","quota_exceeded","temporarily_unavailable","internal_error"] enum: ["invalid_request","invalid_api_key","insufficient_scope","not_found","idempotency_conflict","payload_too_large","unsupported_media_type","rate_limit_exceeded","quota_exceeded","temporarily_unavailable","internal_error"] |
error.message | string | Yes | — |
error.request_id | string | Yes | pattern: ^req_[a-zA-Z0-9_-]+$ |
error.retry_after_seconds | integer | null | Yes | minimum: 0 |
Full canonical schema JSON
{
"type": "object",
"properties": {
"error": {
"type": "object",
"properties": {
"code": {
"type": "string",
"enum": [
"invalid_request",
"invalid_api_key",
"insufficient_scope",
"not_found",
"idempotency_conflict",
"payload_too_large",
"unsupported_media_type",
"rate_limit_exceeded",
"quota_exceeded",
"temporarily_unavailable",
"internal_error"
]
},
"message": {
"type": "string"
},
"request_id": {
"type": "string",
"pattern": "^req_[a-zA-Z0-9_-]+$"
},
"retry_after_seconds": {
"type": [
"integer",
"null"
],
"minimum": 0
}
},
"required": [
"code",
"message",
"request_id",
"retry_after_seconds"
],
"additionalProperties": false
}
},
"required": [
"error"
],
"additionalProperties": false,
"description": "No secrets, SQL, or stack traces. retry_after_seconds is non-null for 429/503 and matches Retry-After. Retry rate/503 with bounded backoff and jitter; quota retry waits until period_end or explicit upgrade. 401/403/400/409 are not blind-retryable."
}Possible errors
Every error below uses the Error envelope with a request ID. Retry only when the response’s proposed semantics identify a temporary condition; see errors and versioning for the detailed guidance.
400 synthetic error example
Invalid or unknown parameter/body, duplicated query parameter, malformed or expired cursor.
X-Request-Id — Request correlation identifier; safe to send to support. X-Request-Credits-Remaining — Organization credits remaining after this request. Present only after successful key authentication. X-Request-Credits-Charged — 0 or 1 for this response; internal cache hits count, idempotent batch replays do not. Cache-Control — private, no-store; key-specific metadata must never enter a shared HTTP cache. Server-side data caching is separate.
{
"error": {
"code": "invalid_request",
"message": "Synthetic example: Invalid or unknown parameter/body, duplicated query parameter, malformed or expired cursor.",
"request_id": "req_example",
"retry_after_seconds": null
}
}401 synthetic error example
Missing, invalid, expired or revoked API key.
X-Request-Id — Request correlation identifier; safe to send to support. X-Request-Credits-Remaining — Organization credits remaining after this request. Present only after successful key authentication. X-Request-Credits-Charged — 0 or 1 for this response; internal cache hits count, idempotent batch replays do not. Cache-Control — private, no-store; key-specific metadata must never enter a shared HTTP cache. Server-side data caching is separate.
{
"error": {
"code": "invalid_api_key",
"message": "Synthetic example: Missing, invalid, expired or revoked API key.",
"request_id": "req_example",
"retry_after_seconds": null
}
}403 synthetic error example
Authenticated key lacks endpoint scope or entitlement.
X-Request-Id — Request correlation identifier; safe to send to support. X-Request-Credits-Remaining — Organization credits remaining after this request. Present only after successful key authentication. X-Request-Credits-Charged — 0 or 1 for this response; internal cache hits count, idempotent batch replays do not. Cache-Control — private, no-store; key-specific metadata must never enter a shared HTTP cache. Server-side data caching is separate.
{
"error": {
"code": "insufficient_scope",
"message": "Synthetic example: Authenticated key lacks endpoint scope or entitlement.",
"request_id": "req_example",
"retry_after_seconds": null
}
}409 synthetic error example
Idempotency key reused with a different normalized batch body.
X-Request-Id — Request correlation identifier; safe to send to support. X-Request-Credits-Remaining — Organization credits remaining after this request. Present only after successful key authentication. X-Request-Credits-Charged — 0 or 1 for this response; internal cache hits count, idempotent batch replays do not. Cache-Control — private, no-store; key-specific metadata must never enter a shared HTTP cache. Server-side data caching is separate.
{
"error": {
"code": "idempotency_conflict",
"message": "Synthetic example: Idempotency key reused with a different normalized batch body.",
"request_id": "req_example",
"retry_after_seconds": null
}
}413 synthetic error example
JSON body exceeds 16 KiB.
X-Request-Id — Request correlation identifier; safe to send to support. X-Request-Credits-Remaining — Organization credits remaining after this request. Present only after successful key authentication. X-Request-Credits-Charged — 0 or 1 for this response; internal cache hits count, idempotent batch replays do not. Cache-Control — private, no-store; key-specific metadata must never enter a shared HTTP cache. Server-side data caching is separate.
{
"error": {
"code": "payload_too_large",
"message": "Synthetic example: JSON body exceeds 16 KiB.",
"request_id": "req_example",
"retry_after_seconds": null
}
}415 synthetic error example
Content-Type must be application/json.
X-Request-Id — Request correlation identifier; safe to send to support. X-Request-Credits-Remaining — Organization credits remaining after this request. Present only after successful key authentication. X-Request-Credits-Charged — 0 or 1 for this response; internal cache hits count, idempotent batch replays do not. Cache-Control — private, no-store; key-specific metadata must never enter a shared HTTP cache. Server-side data caching is separate.
{
"error": {
"code": "unsupported_media_type",
"message": "Synthetic example: Content-Type must be application/json.",
"request_id": "req_example",
"retry_after_seconds": null
}
}429 synthetic error example
rate_limit_exceeded or quota_exceeded; distinct codes and Retry-After.
X-Request-Id — Request correlation identifier; safe to send to support. X-Request-Credits-Remaining — Organization credits remaining after this request. Present only after successful key authentication. X-Request-Credits-Charged — 0 or 1 for this response; internal cache hits count, idempotent batch replays do not. Cache-Control — private, no-store; key-specific metadata must never enter a shared HTTP cache. Server-side data caching is separate. Retry-After — Whole seconds until retry.
{
"error": {
"code": "rate_limit_exceeded",
"message": "Synthetic example: rate_limit_exceeded or quota_exceeded; distinct codes and Retry-After.",
"request_id": "req_example",
"retry_after_seconds": 60
}
}500 synthetic error example
Unexpected internal failure; no sensitive details and zero credits.
X-Request-Id — Request correlation identifier; safe to send to support. X-Request-Credits-Remaining — Organization credits remaining after this request. Present only after successful key authentication. X-Request-Credits-Charged — 0 or 1 for this response; internal cache hits count, idempotent batch replays do not. Cache-Control — private, no-store; key-specific metadata must never enter a shared HTTP cache. Server-side data caching is separate.
{
"error": {
"code": "internal_error",
"message": "Synthetic example: Unexpected internal failure; no sensitive details and zero credits.",
"request_id": "req_example",
"retry_after_seconds": null
}
}503 synthetic error example
temporarily_unavailable: metering, key state, or serving dependency unavailable; fail closed and charge zero.
X-Request-Id — Request correlation identifier; safe to send to support. X-Request-Credits-Remaining — Organization credits remaining after this request. Present only after successful key authentication. X-Request-Credits-Charged — 0 or 1 for this response; internal cache hits count, idempotent batch replays do not. Cache-Control — private, no-store; key-specific metadata must never enter a shared HTTP cache. Server-side data caching is separate. Retry-After — Whole seconds until retry.
{
"error": {
"code": "temporarily_unavailable",
"message": "Synthetic example: temporarily_unavailable: metering, key state, or serving dependency unavailable; fail closed and charge zero.",
"request_id": "req_example",
"retry_after_seconds": 30
}
}