{"openapi":"3.1.0","info":{"title":"exchangerate.dev","description":"Live indicative foreign-exchange rates for developers. Explicit `source` and `market_session` labels on every response — live intraday (~60s) on trading days for all currencies, with ECB daily fallback in the 144-currency catalog (10296 unique pairs). Free tier: 10,000 calls/month, no card. Live rates 15 minutes delayed. MCP server: https://api.exchangerate.dev/v1/mcp/ · Docs: https://exchangerate.dev/docs","contact":{"url":"https://exchangerate.dev/docs"},"version":"1.0"},"paths":{"/health":{"get":{"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Health Health Get"}}}}}}},"/status":{"get":{"summary":"Status","description":"Real readiness probe — DB + Redis reachability + live-data freshness. Public and unmetered\n(a root path bypasses the /v1 gate). Powers the public status page; no fabricated history.","operationId":"status_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/currencies":{"get":{"summary":"Currencies","description":"Supported currencies. BGN is fixed to the euro (1.95583 BGN per EUR, see `fixed_to_euro`): its rates follow the euro and are not a live market rate.","operationId":"currencies_v1_currencies_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrenciesResponse"}}}},"400":{"description":"Bad request. Codes include invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, unsupported_interval, unsupported_pair_interval and unsupported_index_interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"plan_gated: the caller's plan does not include this interval or history depth; forbidden: the request did not pass through the public origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found, e.g. unknown_index or no_data_for_date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit or quota exceeded: rate_limited (per-minute limit, X-RateLimit-Scope tier-rate-minute), ip_rate_limited (keyless per-IP hourly cap, anon-ip-hour) or quota_exceeded (monthly quota, tier-quota-month). Wait Retry-After seconds; do not retry a monthly quota error automatically. quota_unavailable means the quota store could not be read; retry after Retry-After.","headers":{"X-RateLimit-Limit":{"description":"Limit for the window named by X-RateLimit-Scope.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets.","schema":{"type":"integer"}},"X-RateLimit-Scope":{"description":"Which limit applied: anon-ip-hour, tier-rate-minute or tier-quota-month.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The operation failed internally.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"A required data source or feature is temporarily unavailable, e.g. data_unavailable, live_unavailable, source_unavailable or service_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/latest/{path_base}":{"get":{"summary":"Latest","operationId":"latest_v1_latest__path_base__get","parameters":[{"name":"path_base","in":"path","required":true,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Base"}},{"name":"base","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base"}},{"name":"symbols","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Symbols"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LatestResponse"}}}},"400":{"description":"Bad request. Codes include invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, unsupported_interval, unsupported_pair_interval and unsupported_index_interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"plan_gated: the caller's plan does not include this interval or history depth; forbidden: the request did not pass through the public origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found, e.g. unknown_index or no_data_for_date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit or quota exceeded: rate_limited (per-minute limit, X-RateLimit-Scope tier-rate-minute), ip_rate_limited (keyless per-IP hourly cap, anon-ip-hour) or quota_exceeded (monthly quota, tier-quota-month). Wait Retry-After seconds; do not retry a monthly quota error automatically. quota_unavailable means the quota store could not be read; retry after Retry-After.","headers":{"X-RateLimit-Limit":{"description":"Limit for the window named by X-RateLimit-Scope.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets.","schema":{"type":"integer"}},"X-RateLimit-Scope":{"description":"Which limit applied: anon-ip-hour, tier-rate-minute or tier-quota-month.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The operation failed internally.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"A required data source or feature is temporarily unavailable, e.g. data_unavailable, live_unavailable, source_unavailable or service_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/latest":{"get":{"summary":"Latest","operationId":"latest_v1_latest_get","parameters":[{"name":"path_base","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Base"}},{"name":"base","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base"}},{"name":"symbols","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Symbols"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LatestResponse"}}}},"400":{"description":"Bad request. Codes include invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, unsupported_interval, unsupported_pair_interval and unsupported_index_interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"plan_gated: the caller's plan does not include this interval or history depth; forbidden: the request did not pass through the public origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found, e.g. unknown_index or no_data_for_date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit or quota exceeded: rate_limited (per-minute limit, X-RateLimit-Scope tier-rate-minute), ip_rate_limited (keyless per-IP hourly cap, anon-ip-hour) or quota_exceeded (monthly quota, tier-quota-month). Wait Retry-After seconds; do not retry a monthly quota error automatically. quota_unavailable means the quota store could not be read; retry after Retry-After.","headers":{"X-RateLimit-Limit":{"description":"Limit for the window named by X-RateLimit-Scope.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets.","schema":{"type":"integer"}},"X-RateLimit-Scope":{"description":"Which limit applied: anon-ip-hour, tier-rate-minute or tier-quota-month.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The operation failed internally.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"A required data source or feature is temporarily unavailable, e.g. data_unavailable, live_unavailable, source_unavailable or service_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/convert/{from_ccy}/{to_ccy}/{amount}":{"get":{"summary":"Convert","operationId":"convert_v1_convert__from_ccy___to_ccy___amount__get","parameters":[{"name":"from_ccy","in":"path","required":true,"schema":{"type":"string","title":"From Ccy"}},{"name":"to_ccy","in":"path","required":true,"schema":{"type":"string","title":"To Ccy"}},{"name":"amount","in":"path","required":true,"schema":{"anyOf":[{"type":"number"},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Amount"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConvertResponse"}}}},"400":{"description":"Bad request. Codes include invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, unsupported_interval, unsupported_pair_interval and unsupported_index_interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"plan_gated: the caller's plan does not include this interval or history depth; forbidden: the request did not pass through the public origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found, e.g. unknown_index or no_data_for_date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit or quota exceeded: rate_limited (per-minute limit, X-RateLimit-Scope tier-rate-minute), ip_rate_limited (keyless per-IP hourly cap, anon-ip-hour) or quota_exceeded (monthly quota, tier-quota-month). Wait Retry-After seconds; do not retry a monthly quota error automatically. quota_unavailable means the quota store could not be read; retry after Retry-After.","headers":{"X-RateLimit-Limit":{"description":"Limit for the window named by X-RateLimit-Scope.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets.","schema":{"type":"integer"}},"X-RateLimit-Scope":{"description":"Which limit applied: anon-ip-hour, tier-rate-minute or tier-quota-month.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The operation failed internally.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"A required data source or feature is temporarily unavailable, e.g. data_unavailable, live_unavailable, source_unavailable or service_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/convert/{from_ccy}/{to_ccy}":{"get":{"summary":"Convert","operationId":"convert_v1_convert__from_ccy___to_ccy__get","parameters":[{"name":"from_ccy","in":"path","required":true,"schema":{"type":"string","title":"From Ccy"}},{"name":"to_ccy","in":"path","required":true,"schema":{"type":"string","title":"To Ccy"}},{"name":"amount","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"default":"1","title":"Amount"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConvertResponse"}}}},"400":{"description":"Bad request. Codes include invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, unsupported_interval, unsupported_pair_interval and unsupported_index_interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"plan_gated: the caller's plan does not include this interval or history depth; forbidden: the request did not pass through the public origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found, e.g. unknown_index or no_data_for_date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit or quota exceeded: rate_limited (per-minute limit, X-RateLimit-Scope tier-rate-minute), ip_rate_limited (keyless per-IP hourly cap, anon-ip-hour) or quota_exceeded (monthly quota, tier-quota-month). Wait Retry-After seconds; do not retry a monthly quota error automatically. quota_unavailable means the quota store could not be read; retry after Retry-After.","headers":{"X-RateLimit-Limit":{"description":"Limit for the window named by X-RateLimit-Scope.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets.","schema":{"type":"integer"}},"X-RateLimit-Scope":{"description":"Which limit applied: anon-ip-hour, tier-rate-minute or tier-quota-month.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The operation failed internally.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"A required data source or feature is temporarily unavailable, e.g. data_unavailable, live_unavailable, source_unavailable or service_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/convert":{"post":{"summary":"Convert Batch","operationId":"convert_batch_v1_convert_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConvertBatchRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConvertBatchResponse"}}}},"400":{"description":"Bad request. Codes include invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, unsupported_interval, unsupported_pair_interval and unsupported_index_interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"plan_gated: the caller's plan does not include this interval or history depth; forbidden: the request did not pass through the public origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found, e.g. unknown_index or no_data_for_date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit or quota exceeded: rate_limited (per-minute limit, X-RateLimit-Scope tier-rate-minute), ip_rate_limited (keyless per-IP hourly cap, anon-ip-hour) or quota_exceeded (monthly quota, tier-quota-month). Wait Retry-After seconds; do not retry a monthly quota error automatically. quota_unavailable means the quota store could not be read; retry after Retry-After.","headers":{"X-RateLimit-Limit":{"description":"Limit for the window named by X-RateLimit-Scope.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets.","schema":{"type":"integer"}},"X-RateLimit-Scope":{"description":"Which limit applied: anon-ip-hour, tier-rate-minute or tier-quota-month.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The operation failed internally.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"A required data source or feature is temporarily unavailable, e.g. data_unavailable, live_unavailable, source_unavailable or service_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/range":{"get":{"summary":"Range Endpoint","operationId":"range_endpoint_v1_range_get","parameters":[{"name":"symbols","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Symbols"}},{"name":"start_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Date"}},{"name":"end_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"End Date"}},{"name":"base","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"format","in":"query","required":false,"schema":{"enum":["json","csv","parquet"],"type":"string","default":"json","title":"Format"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RangeResponse"}},"text/csv":{},"application/vnd.apache.parquet":{}}},"400":{"description":"Bad request. Codes include invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, unsupported_interval, unsupported_pair_interval and unsupported_index_interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"plan_gated: the caller's plan does not include this interval or history depth; forbidden: the request did not pass through the public origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found, e.g. unknown_index or no_data_for_date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit or quota exceeded: rate_limited (per-minute limit, X-RateLimit-Scope tier-rate-minute), ip_rate_limited (keyless per-IP hourly cap, anon-ip-hour) or quota_exceeded (monthly quota, tier-quota-month). Wait Retry-After seconds; do not retry a monthly quota error automatically. quota_unavailable means the quota store could not be read; retry after Retry-After.","headers":{"X-RateLimit-Limit":{"description":"Limit for the window named by X-RateLimit-Scope.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets.","schema":{"type":"integer"}},"X-RateLimit-Scope":{"description":"Which limit applied: anon-ip-hour, tier-rate-minute or tier-quota-month.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The operation failed internally.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"A required data source or feature is temporarily unavailable, e.g. data_unavailable, live_unavailable, source_unavailable or service_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/timeseries":{"get":{"summary":"Timeseries Endpoint","operationId":"timeseries_endpoint_v1_timeseries_get","parameters":[{"name":"symbols","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Symbols"}},{"name":"interval","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Interval"}},{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"From"}},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"To"}},{"name":"base","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"format","in":"query","required":false,"schema":{"enum":["json","csv","parquet"],"type":"string","default":"json","title":"Format"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeseriesResponse"}},"text/csv":{},"application/vnd.apache.parquet":{}}},"400":{"description":"Bad request. Codes include invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, unsupported_interval, unsupported_pair_interval and unsupported_index_interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"plan_gated: the caller's plan does not include this interval or history depth; forbidden: the request did not pass through the public origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found, e.g. unknown_index or no_data_for_date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit or quota exceeded: rate_limited (per-minute limit, X-RateLimit-Scope tier-rate-minute), ip_rate_limited (keyless per-IP hourly cap, anon-ip-hour) or quota_exceeded (monthly quota, tier-quota-month). Wait Retry-After seconds; do not retry a monthly quota error automatically. quota_unavailable means the quota store could not be read; retry after Retry-After.","headers":{"X-RateLimit-Limit":{"description":"Limit for the window named by X-RateLimit-Scope.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets.","schema":{"type":"integer"}},"X-RateLimit-Scope":{"description":"Which limit applied: anon-ip-hour, tier-rate-minute or tier-quota-month.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The operation failed internally.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"A required data source or feature is temporarily unavailable, e.g. data_unavailable, live_unavailable, source_unavailable or service_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/indices/{index_slug}":{"get":{"summary":"Index Snapshot","operationId":"index_snapshot_v1_indices__index_slug__get","parameters":[{"name":"index_slug","in":"path","required":true,"schema":{"type":"string","title":"Index Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IndexSnapshotResponse"}}}},"400":{"description":"Bad request. Codes include invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, unsupported_interval, unsupported_pair_interval and unsupported_index_interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"plan_gated: the caller's plan does not include this interval or history depth; forbidden: the request did not pass through the public origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found, e.g. unknown_index or no_data_for_date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit or quota exceeded: rate_limited (per-minute limit, X-RateLimit-Scope tier-rate-minute), ip_rate_limited (keyless per-IP hourly cap, anon-ip-hour) or quota_exceeded (monthly quota, tier-quota-month). Wait Retry-After seconds; do not retry a monthly quota error automatically. quota_unavailable means the quota store could not be read; retry after Retry-After.","headers":{"X-RateLimit-Limit":{"description":"Limit for the window named by X-RateLimit-Scope.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets.","schema":{"type":"integer"}},"X-RateLimit-Scope":{"description":"Which limit applied: anon-ip-hour, tier-rate-minute or tier-quota-month.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The operation failed internally.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"A required data source or feature is temporarily unavailable, e.g. data_unavailable, live_unavailable, source_unavailable or service_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/indices/{index_slug}/timeseries":{"get":{"summary":"Index Timeseries","operationId":"index_timeseries_v1_indices__index_slug__timeseries_get","parameters":[{"name":"index_slug","in":"path","required":true,"schema":{"type":"string","title":"Index Slug"}},{"name":"interval","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Interval"}},{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"From"}},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"To"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IndexTimeseriesResponse"}}}},"400":{"description":"Bad request. Codes include invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, unsupported_interval, unsupported_pair_interval and unsupported_index_interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"plan_gated: the caller's plan does not include this interval or history depth; forbidden: the request did not pass through the public origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found, e.g. unknown_index or no_data_for_date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit or quota exceeded: rate_limited (per-minute limit, X-RateLimit-Scope tier-rate-minute), ip_rate_limited (keyless per-IP hourly cap, anon-ip-hour) or quota_exceeded (monthly quota, tier-quota-month). Wait Retry-After seconds; do not retry a monthly quota error automatically. quota_unavailable means the quota store could not be read; retry after Retry-After.","headers":{"X-RateLimit-Limit":{"description":"Limit for the window named by X-RateLimit-Scope.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets.","schema":{"type":"integer"}},"X-RateLimit-Scope":{"description":"Which limit applied: anon-ip-hour, tier-rate-minute or tier-quota-month.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The operation failed internally.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"A required data source or feature is temporarily unavailable, e.g. data_unavailable, live_unavailable, source_unavailable or service_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/account/provision":{"post":{"summary":"Provision","description":"Idempotent onboarding: create org if absent; issue first key if absent. Plaintext is\nalso re-revealable later via GET /v1/account (at-rest encrypted; dashboard full-key copy).","operationId":"provision_v1_account_provision_post","requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ProvisionRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreatedResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/checkout":{"post":{"summary":"Account Checkout","description":"Open the selected safe billing action for the API key's organization.","operationId":"account_checkout_v1_account_checkout_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/checkout-session":{"post":{"summary":"Account Checkout Session","description":"Website checkout: ownership comes exclusively from the verified login.","operationId":"account_checkout_session_v1_account_checkout_session_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account":{"get":{"summary":"Account","description":"Read-only account summary: org, active key, monthly usage.","operationId":"account_v1_account_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountResponse"}}}}}},"delete":{"summary":"Delete Account","description":"Self-serve account deletion.\n\nCancels the Stripe subscription immediately (if present), then purges all org data\nin one transaction: usage_daily → usage_monthly → api_keys → organizations.\nDoes NOT delete auth.users — the web BFF does that with the service role.\nDoes NOT touch webhook_events (global Stripe idempotency table).\n\nAbort policy: if Stripe cancel fails for any reason other than \"already gone\",\nreturns 502 and deletes NOTHING (never orphan an active subscription).","operationId":"delete_account_v1_account_delete","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteAccountResponse"}}}}}}},"/v1/account/usage/daily":{"get":{"summary":"Account Usage Daily","description":"Dashboard only: requires the signed-in dashboard session token, not an API key. API keys get 401 invalid_session_token. Zero-filled daily served requests and rate-limited hits for the signed-in account.","operationId":"account_usage_daily_v1_account_usage_daily_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DailyUsageResponse"}}}},"401":{"description":"Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"no_account: the signed-in user has no organization yet."},"503":{"description":"auth_unavailable: the session could not be verified; retry."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/account/keys":{"get":{"summary":"List Named Keys","operationId":"list_named_keys_v1_account_keys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Named Keys V1 Account Keys Get"}}}}}},"post":{"summary":"Manage Named Key","operationId":"manage_named_key_v1_account_keys_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NamedKeyRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Manage Named Key V1 Account Keys Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/keys/rotate":{"post":{"summary":"Rotate Key","description":"Revoke the current active key (24-hour grace) and issue a new one. Returns the plaintext,\nwhich is also re-revealable later via GET /v1/account (at-rest encrypted).","operationId":"rotate_key_v1_keys_rotate_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreatedResponse"}}}}}}},"/v1/keys":{"delete":{"summary":"Revoke Key","description":"Revoke the org's active key immediately (revoked_at=now()).","operationId":"revoke_key_v1_keys_delete","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Revoke Key V1 Keys Delete"}}}}}}},"/v1/consent":{"post":{"summary":"Record Consent","description":"Record a policy acceptance for the calling user.","operationId":"record_consent_v1_consent_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsentRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/rate/{slug}":{"get":{"summary":"Rate","operationId":"rate_v1_rate__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateResponse"}}}},"400":{"description":"Bad request. Codes include invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, unsupported_interval, unsupported_pair_interval and unsupported_index_interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"plan_gated: the caller's plan does not include this interval or history depth; forbidden: the request did not pass through the public origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found, e.g. unknown_index or no_data_for_date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit or quota exceeded: rate_limited (per-minute limit, X-RateLimit-Scope tier-rate-minute), ip_rate_limited (keyless per-IP hourly cap, anon-ip-hour) or quota_exceeded (monthly quota, tier-quota-month). Wait Retry-After seconds; do not retry a monthly quota error automatically. quota_unavailable means the quota store could not be read; retry after Retry-After.","headers":{"X-RateLimit-Limit":{"description":"Limit for the window named by X-RateLimit-Scope.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets.","schema":{"type":"integer"}},"X-RateLimit-Scope":{"description":"Which limit applied: anon-ip-hour, tier-rate-minute or tier-quota-month.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The operation failed internally.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"A required data source or feature is temporarily unavailable, e.g. data_unavailable, live_unavailable, source_unavailable or service_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/{date}/{path_base}":{"get":{"summary":"Historical","operationId":"historical_v1__date___path_base__get","parameters":[{"name":"date","in":"path","required":true,"schema":{"type":"string","title":"Date"}},{"name":"path_base","in":"path","required":true,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Base"}},{"name":"base","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base"}},{"name":"symbols","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Symbols"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HistoricalResponse"}}}},"400":{"description":"Bad request. Codes include invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, unsupported_interval, unsupported_pair_interval and unsupported_index_interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"plan_gated: the caller's plan does not include this interval or history depth; forbidden: the request did not pass through the public origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found, e.g. unknown_index or no_data_for_date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit or quota exceeded: rate_limited (per-minute limit, X-RateLimit-Scope tier-rate-minute), ip_rate_limited (keyless per-IP hourly cap, anon-ip-hour) or quota_exceeded (monthly quota, tier-quota-month). Wait Retry-After seconds; do not retry a monthly quota error automatically. quota_unavailable means the quota store could not be read; retry after Retry-After.","headers":{"X-RateLimit-Limit":{"description":"Limit for the window named by X-RateLimit-Scope.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets.","schema":{"type":"integer"}},"X-RateLimit-Scope":{"description":"Which limit applied: anon-ip-hour, tier-rate-minute or tier-quota-month.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The operation failed internally.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"A required data source or feature is temporarily unavailable, e.g. data_unavailable, live_unavailable, source_unavailable or service_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/{date}":{"get":{"summary":"Historical","operationId":"historical_v1__date__get","parameters":[{"name":"date","in":"path","required":true,"schema":{"type":"string","title":"Date"}},{"name":"path_base","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Base"}},{"name":"base","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base"}},{"name":"symbols","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Symbols"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HistoricalResponse"}}}},"400":{"description":"Bad request. Codes include invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, unsupported_interval, unsupported_pair_interval and unsupported_index_interval.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"plan_gated: the caller's plan does not include this interval or history depth; forbidden: the request did not pass through the public origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found, e.g. unknown_index or no_data_for_date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit or quota exceeded: rate_limited (per-minute limit, X-RateLimit-Scope tier-rate-minute), ip_rate_limited (keyless per-IP hourly cap, anon-ip-hour) or quota_exceeded (monthly quota, tier-quota-month). Wait Retry-After seconds; do not retry a monthly quota error automatically. quota_unavailable means the quota store could not be read; retry after Retry-After.","headers":{"X-RateLimit-Limit":{"description":"Limit for the window named by X-RateLimit-Scope.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in that window (0 on a 429).","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets.","schema":{"type":"integer"}},"X-RateLimit-Scope":{"description":"Which limit applied: anon-ip-hour, tier-rate-minute or tier-quota-month.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The operation failed internally.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"A required data source or feature is temporarily unavailable, e.g. data_unavailable, live_unavailable, source_unavailable or service_unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"AccountResponse":{"properties":{"result":{"type":"string","title":"Result","default":"success"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"org":{"anyOf":[{"$ref":"#/components/schemas/OrgSummary"},{"type":"null"}]},"key":{"anyOf":[{"$ref":"#/components/schemas/KeySummary"},{"type":"null"}]},"keys":{"items":{"$ref":"#/components/schemas/KeyInventorySummary"},"type":"array","title":"Keys"},"usage":{"anyOf":[{"$ref":"#/components/schemas/UsageSummary"},{"type":"null"}]},"billing":{"anyOf":[{"$ref":"#/components/schemas/BillingSummary"},{"type":"null"}]}},"type":"object","required":["email","org","key","usage"],"title":"AccountResponse"},"ApiKeyCreatedResponse":{"properties":{"result":{"type":"string","title":"Result","default":"success"},"created":{"type":"boolean","title":"Created"},"org_id":{"type":"string","title":"Org Id"},"plaintext":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Plaintext"},"key":{"anyOf":[{"$ref":"#/components/schemas/KeySummary"},{"type":"null"}]}},"type":"object","required":["created","org_id","plaintext","key"],"title":"ApiKeyCreatedResponse"},"BillingSummary":{"properties":{"state":{"type":"string","enum":["none","pending","active","ending","failed","unpaid","ended","complimentary"],"title":"State"},"interval":{"anyOf":[{"type":"string","enum":["monthly","yearly"]},{"type":"null"}],"title":"Interval"},"current_period_end":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Current Period End"},"ends_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ends At"}},"type":"object","required":["state"],"title":"BillingSummary","description":"The account's billing state (docs/BILLING-STATES.md); every screen reads this."},"CheckoutRequest":{"properties":{"plan":{"type":"string","enum":["basic_2026","plus_2026","pro_2026"],"title":"Plan"},"interval":{"type":"string","pattern":"^(monthly|yearly)$","title":"Interval","default":"monthly"}},"additionalProperties":false,"type":"object","required":["plan"],"title":"CheckoutRequest","description":"Selected paid plan; account identity comes from verified server-side auth."},"CheckoutResponse":{"properties":{"result":{"type":"string","title":"Result","default":"success"},"action":{"type":"string","pattern":"^(checkout|manage_subscription)$","title":"Action"},"url":{"type":"string","title":"Url"},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At"}},"type":"object","required":["action","url"],"title":"CheckoutResponse"},"ConsentRequest":{"properties":{"policy_version":{"type":"string","title":"Policy Version"}},"additionalProperties":false,"type":"object","required":["policy_version"],"title":"ConsentRequest"},"ConsentResponse":{"properties":{"result":{"type":"string","title":"Result","default":"success"},"policy_version":{"type":"string","title":"Policy Version"},"accepted_at":{"type":"string","title":"Accepted At"}},"type":"object","required":["policy_version","accepted_at"],"title":"ConsentResponse"},"ConvertBatchRequest":{"properties":{"from":{"type":"string","title":"From"},"pairs":{"items":{"prefixItems":[{"type":"string"},{"anyOf":[{"type":"number"},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}]}],"type":"array","maxItems":2,"minItems":2},"type":"array","title":"Pairs"}},"additionalProperties":false,"type":"object","required":["from","pairs"],"title":"ConvertBatchRequest"},"ConvertBatchResponse":{"properties":{"result":{"type":"string","title":"Result","default":"success"},"from":{"type":"string","title":"From"},"conversions":{"items":{"$ref":"#/components/schemas/ConvertItem"},"type":"array","title":"Conversions"},"source":{"$ref":"#/components/schemas/Source"},"sources":{"additionalProperties":{"$ref":"#/components/schemas/Source"},"type":"object","title":"Sources"},"stale":{"additionalProperties":{"type":"boolean"},"type":"object","title":"Stale"},"market_session":{"$ref":"#/components/schemas/MarketSession"},"timestamp":{"type":"string","title":"Timestamp"},"data_updated_at":{"type":"string","title":"Data Updated At"},"effective_at":{"additionalProperties":{"type":"string"},"type":"object","title":"Effective At"},"notice":{"type":"string","title":"Notice"}},"type":"object","required":["from","conversions","source","sources","stale","market_session","timestamp","data_updated_at","effective_at","notice"],"title":"ConvertBatchResponse"},"ConvertItem":{"properties":{"to":{"type":"string","title":"To"},"amount":{"type":"number","title":"Amount"},"rate":{"type":"number","title":"Rate"},"converted":{"type":"number","title":"Converted"},"derived":{"type":"boolean","title":"Derived"},"derivation_bps_max":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Derivation Bps Max"}},"type":"object","required":["to","amount","rate","converted","derived"],"title":"ConvertItem"},"ConvertResponse":{"properties":{"result":{"type":"string","title":"Result","default":"success"},"from":{"type":"string","title":"From"},"to":{"type":"string","title":"To"},"amount":{"type":"number","title":"Amount"},"rate":{"type":"number","title":"Rate"},"converted":{"type":"number","title":"Converted"},"derived":{"type":"boolean","title":"Derived"},"derivation_bps_max":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Derivation Bps Max"},"source":{"$ref":"#/components/schemas/Source"},"sources":{"additionalProperties":{"$ref":"#/components/schemas/Source"},"type":"object","title":"Sources"},"stale":{"type":"boolean","title":"Stale"},"market_session":{"$ref":"#/components/schemas/MarketSession"},"timestamp":{"type":"string","title":"Timestamp"},"data_updated_at":{"type":"string","title":"Data Updated At"},"notice":{"type":"string","title":"Notice"}},"type":"object","required":["from","to","amount","rate","converted","derived","source","sources","stale","market_session","timestamp","data_updated_at","notice"],"title":"ConvertResponse"},"CurrenciesResponse":{"properties":{"result":{"type":"string","title":"Result","default":"success"},"currencies":{"items":{"$ref":"#/components/schemas/CurrencyInfo"},"type":"array","title":"Currencies"}},"type":"object","required":["currencies"],"title":"CurrenciesResponse"},"CurrencyInfo":{"properties":{"code":{"type":"string","title":"Code"},"name":{"type":"string","title":"Name"},"type":{"type":"string","title":"Type","default":"fiat"},"decimals":{"type":"integer","title":"Decimals"},"minor_units":{"type":"integer","title":"Minor Units"},"is_derived":{"type":"boolean","title":"Is Derived"},"fixed_to_euro":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Fixed To Euro","description":"Set only for a currency fixed to the euro (e.g. BGN): its legal units per 1 EUR. Its rates follow the euro at this fixed rate; they are not an independent market rate. Null for every other currency."}},"type":"object","required":["code","name","decimals","minor_units","is_derived"],"title":"CurrencyInfo"},"DailyUsageEntry":{"properties":{"date":{"type":"string","title":"Date"},"count":{"type":"integer","title":"Count"},"rate_limited":{"type":"integer","title":"Rate Limited"}},"type":"object","required":["date","count","rate_limited"],"title":"DailyUsageEntry"},"DailyUsageResponse":{"properties":{"result":{"type":"string","title":"Result","default":"success"},"tier":{"type":"string","title":"Tier"},"limit":{"type":"integer","title":"Limit"},"month_to_date":{"type":"integer","title":"Month To Date"},"rate_limited_total":{"type":"integer","title":"Rate Limited Total"},"active_streams":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Active Streams"},"max_streams":{"type":"integer","title":"Max Streams"},"days":{"items":{"$ref":"#/components/schemas/DailyUsageEntry"},"type":"array","title":"Days"}},"type":"object","required":["tier","limit","month_to_date","rate_limited_total","max_streams","days"],"title":"DailyUsageResponse"},"DeleteAccountResponse":{"properties":{"result":{"type":"string","title":"Result","default":"success"},"deleted":{"type":"boolean","title":"Deleted","default":true}},"type":"object","title":"DeleteAccountResponse"},"ErrorResponse":{"properties":{"result":{"type":"string","title":"Result","default":"error"},"code":{"type":"string","title":"Code"},"message":{"type":"string","title":"Message"}},"type":"object","required":["code","message"],"title":"ErrorResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HistoricalResponse":{"properties":{"result":{"type":"string","title":"Result","default":"success"},"base":{"type":"string","title":"Base"},"date":{"type":"string","title":"Date"},"source":{"$ref":"#/components/schemas/Source"},"sources":{"additionalProperties":{"$ref":"#/components/schemas/Source"},"type":"object","title":"Sources"},"market_session":{"$ref":"#/components/schemas/MarketSession"},"timestamp":{"type":"string","title":"Timestamp"},"data_updated_at":{"type":"string","title":"Data Updated At"},"is_forward_filled":{"type":"boolean","title":"Is Forward Filled"},"rates":{"additionalProperties":{"type":"number"},"type":"object","title":"Rates"},"derived_symbols":{"items":{"type":"string"},"type":"array","title":"Derived Symbols"},"notice":{"type":"string","title":"Notice"}},"type":"object","required":["base","date","source","sources","market_session","timestamp","data_updated_at","is_forward_filled","rates","derived_symbols","notice"],"title":"HistoricalResponse"},"IndexConstituent":{"properties":{"currency":{"type":"string","title":"Currency"},"weight":{"type":"number","title":"Weight"},"rate":{"type":"number","title":"Rate"},"effective_at":{"type":"string","title":"Effective At"},"contribution":{"type":"number","title":"Contribution"}},"type":"object","required":["currency","weight","rate","effective_at","contribution"],"title":"IndexConstituent"},"IndexSnapshotResponse":{"properties":{"result":{"type":"string","title":"Result","default":"success"},"index":{"type":"string","title":"Index"},"name":{"type":"string","title":"Name"},"methodology_version":{"type":"string","title":"Methodology Version"},"value":{"type":"number","title":"Value"},"timestamp":{"type":"string","title":"Timestamp"},"data_updated_at":{"type":"string","title":"Data Updated At"},"source":{"$ref":"#/components/schemas/Source"},"source_type":{"type":"string","enum":["market","reference"],"title":"Source Type"},"market_session":{"$ref":"#/components/schemas/MarketSession"},"stale":{"type":"boolean","title":"Stale"},"base_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base Date"},"weights":{"additionalProperties":{"type":"number"},"type":"object","title":"Weights"},"constituents":{"items":{"$ref":"#/components/schemas/IndexConstituent"},"type":"array","title":"Constituents"},"notice":{"type":"string","title":"Notice"}},"type":"object","required":["index","name","methodology_version","value","timestamp","data_updated_at","source","source_type","market_session","stale","base_date","weights","constituents","notice"],"title":"IndexSnapshotResponse"},"IndexTimeseriesResponse":{"properties":{"result":{"type":"string","title":"Result","default":"success"},"index":{"type":"string","title":"Index"},"name":{"type":"string","title":"Name"},"methodology_version":{"type":"string","title":"Methodology Version"},"interval":{"type":"string","enum":["1m","5m","15m","1h","4h","1d"],"title":"Interval"},"from":{"type":"string","title":"From"},"to":{"type":"string","title":"To"},"base_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base Date"},"weights":{"additionalProperties":{"type":"number"},"type":"object","title":"Weights"},"data":{"items":{"$ref":"#/components/schemas/IndexTimeseriesRow"},"type":"array","title":"Data"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"has_more":{"type":"boolean","title":"Has More","default":false},"notice":{"type":"string","title":"Notice"}},"type":"object","required":["index","name","methodology_version","interval","from","to","base_date","weights","data","notice"],"title":"IndexTimeseriesResponse"},"IndexTimeseriesRow":{"properties":{"timestamp":{"type":"string","title":"Timestamp"},"value":{"type":"number","title":"Value"},"data_updated_at":{"type":"string","title":"Data Updated At"},"source":{"$ref":"#/components/schemas/Source"},"source_type":{"type":"string","enum":["market","reference"],"title":"Source Type"},"market_session":{"$ref":"#/components/schemas/MarketSession"}},"type":"object","required":["timestamp","value","data_updated_at","source","source_type","market_session"],"title":"IndexTimeseriesRow"},"KeyInventorySummary":{"properties":{"id":{"type":"string","title":"Id"},"prefix":{"type":"string","title":"Prefix"},"created_at":{"type":"string","title":"Created At"},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Used At"},"revoked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revoked At"}},"type":"object","required":["id","prefix","created_at"],"title":"KeyInventorySummary"},"KeySummary":{"properties":{"first_success_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Success At"},"prefix":{"type":"string","title":"Prefix"},"plaintext":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Plaintext"},"created_at":{"type":"string","title":"Created At"},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Used At"}},"type":"object","required":["prefix","created_at"],"title":"KeySummary"},"LatestResponse":{"properties":{"result":{"type":"string","title":"Result","default":"success"},"base":{"type":"string","title":"Base"},"source":{"$ref":"#/components/schemas/Source"},"sources":{"additionalProperties":{"$ref":"#/components/schemas/Source"},"type":"object","title":"Sources"},"market_session":{"$ref":"#/components/schemas/MarketSession"},"timestamp":{"type":"string","title":"Timestamp"},"data_updated_at":{"type":"string","title":"Data Updated At"},"effective_at":{"additionalProperties":{"type":"string"},"type":"object","title":"Effective At"},"rates":{"additionalProperties":{"type":"number"},"type":"object","title":"Rates"},"stale":{"additionalProperties":{"type":"boolean"},"type":"object","title":"Stale"},"derived_symbols":{"items":{"type":"string"},"type":"array","title":"Derived Symbols"},"notice":{"type":"string","title":"Notice"}},"type":"object","required":["base","source","sources","market_session","timestamp","data_updated_at","effective_at","rates","stale","derived_symbols","notice"],"title":"LatestResponse"},"MarketSession":{"type":"string","enum":["open","weekend","interbank_closed"],"title":"MarketSession","description":"Computed from a clock, no feed (D9). `interbank_closed` = a known non-weekend closure\n(e.g. an ECB/TARGET2 holiday detected via an empty Tier-C response — INGESTION §4)."},"NamedKeyRequest":{"properties":{"action":{"type":"string","enum":["create","rename","rotate","revoke"],"title":"Action"},"id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Id"},"request_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Request Id"},"name":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Name"}},"additionalProperties":false,"type":"object","required":["action"],"title":"NamedKeyRequest"},"OrgSummary":{"properties":{"id":{"type":"string","title":"Id"},"tier":{"type":"string","title":"Tier"},"status":{"type":"string","title":"Status"},"stream_connections":{"type":"integer","title":"Stream Connections","default":0},"stream_pairs_per_connection":{"type":"integer","title":"Stream Pairs Per Connection","default":0}},"type":"object","required":["id","tier","status"],"title":"OrgSummary"},"ProvisionRequest":{"properties":{"defer_key":{"type":"boolean","title":"Defer Key","default":false},"signup_attribution":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Signup Attribution"},"marketing_consent":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Marketing Consent"}},"additionalProperties":false,"type":"object","title":"ProvisionRequest"},"RangeResponse":{"properties":{"result":{"type":"string","title":"Result","default":"success"},"base":{"type":"string","title":"Base"},"start_date":{"type":"string","title":"Start Date"},"end_date":{"type":"string","title":"End Date"},"data":{"items":{"$ref":"#/components/schemas/RangeRow"},"type":"array","title":"Data"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"has_more":{"type":"boolean","title":"Has More","default":false},"notice":{"type":"string","title":"Notice"}},"type":"object","required":["base","start_date","end_date","data","notice"],"title":"RangeResponse"},"RangeRow":{"properties":{"date":{"type":"string","title":"Date"},"rates":{"additionalProperties":{"type":"number"},"type":"object","title":"Rates"},"source":{"$ref":"#/components/schemas/Source"},"is_forward_filled":{"type":"boolean","title":"Is Forward Filled"},"derived_symbols":{"items":{"type":"string"},"type":"array","title":"Derived Symbols"}},"type":"object","required":["date","rates","source","is_forward_filled","derived_symbols"],"title":"RangeRow"},"RateResponse":{"properties":{"result":{"type":"string","title":"Result","default":"success"},"pair":{"type":"string","title":"Pair"},"base":{"type":"string","title":"Base"},"quote":{"type":"string","title":"Quote"},"rate":{"type":"number","title":"Rate"},"source":{"$ref":"#/components/schemas/Source"},"sources":{"additionalProperties":{"$ref":"#/components/schemas/Source"},"type":"object","title":"Sources"},"stale":{"type":"boolean","title":"Stale"},"market_session":{"$ref":"#/components/schemas/MarketSession"},"timestamp":{"type":"string","title":"Timestamp"},"data_updated_at":{"type":"string","title":"Data Updated At"},"derived":{"type":"boolean","title":"Derived"},"derivation_bps_max":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Derivation Bps Max"},"notice":{"type":"string","title":"Notice"}},"type":"object","required":["pair","base","quote","rate","source","sources","stale","market_session","timestamp","data_updated_at","derived","notice"],"title":"RateResponse"},"Source":{"type":"string","enum":["live","ecb_daily","market_daily"],"title":"Source","description":"Public `source` enum — wire contract (D2). NO `cached` value (cache lives in X-Cache).\n\n`ecb_daily` is the only reference source (October 2026).\n`market_daily` labels the stored daily close of the live market feed, for the currencies with\nno reference fix, in date history and 1d time series; it is never a live rate."},"TimeseriesResponse":{"properties":{"result":{"type":"string","title":"Result","default":"success"},"base":{"type":"string","title":"Base"},"symbols":{"items":{"type":"string"},"type":"array","title":"Symbols"},"interval":{"type":"string","enum":["1m","5m","15m","1h","4h","1d"],"title":"Interval"},"from":{"type":"string","title":"From"},"to":{"type":"string","title":"To"},"data":{"items":{"$ref":"#/components/schemas/TimeseriesRow"},"type":"array","title":"Data"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"has_more":{"type":"boolean","title":"Has More","default":false},"notice":{"type":"string","title":"Notice"}},"type":"object","required":["base","symbols","interval","from","to","data","notice"],"title":"TimeseriesResponse"},"TimeseriesRow":{"properties":{"timestamp":{"type":"string","title":"Timestamp"},"effective_at":{"additionalProperties":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":"object","title":"Effective At"},"rates":{"additionalProperties":{"type":"number"},"type":"object","title":"Rates"},"source":{"$ref":"#/components/schemas/Source"},"source_type":{"type":"string","enum":["market","reference"],"title":"Source Type"},"market_session":{"$ref":"#/components/schemas/MarketSession"},"derived_symbols":{"items":{"type":"string"},"type":"array","title":"Derived Symbols"}},"type":"object","required":["timestamp","effective_at","rates","source","source_type","market_session","derived_symbols"],"title":"TimeseriesRow"},"UsageSummary":{"properties":{"calls_this_month":{"type":"integer","title":"Calls This Month"},"limit":{"type":"integer","title":"Limit"},"resets_on":{"type":"string","title":"Resets On"}},"type":"object","required":["calls_this_month","limit","resets_on"],"title":"UsageSummary"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}