openapi: 3.0.3 info: title: 'FXProof API Documentation' description: 'FXProof API helps teams automate proof work: discover valid datasets, retrieve reference rates when needed, open or reuse proof bundles, download ready files, and verify FXProof PDFs. After authentication, rates and proof bundle routes expose quota state with X-Quota-Limit, X-Quota-Remaining, and X-Quota-Reset.' version: 1.0.0 servers: - url: 'https://fxproof.org' tags: - name: Account description: '' - name: Authentication description: '' - name: 'Proof Bundles' description: '' - name: 'Public Verification' description: '' - name: Rates description: '' - name: System description: '' components: securitySchemes: default: type: http scheme: bearer description: 'Call POST /api/v1/tokens over HTTPS to get a short-lived Bearer token. Use it for protected endpoints.' security: - default: [] paths: /api/v1/user: get: summary: "Get the authenticated user's account and quota summary." operationId: getTheAuthenticatedUsersAccountAndQuotaSummary description: '' parameters: [] responses: 200: description: 'Profile payload' content: application/json: schema: type: object example: data: id: 1 name: 'API User' email: api-user@example.com email_verified_at: '2026-03-30T12:00:00Z' subscriptions: - name: default provider: paddle status: active ends_at: null current_period_start: null current_period_end: null entitlements: - product: Basic granted_at: '2026-03-01T00:00:00Z' expires_at: null current_period: start: '2026-03-01' end: '2026-03-31' reset_at: '2026-04-01T00:00:00Z' usage: api_calls: 1 proofs: 1 limits: api_calls: 1500 proofs: 5 rpm: 10 parallel_streams: 1 history_years: 1 history_days: 366 history_earliest_date: '2025-03-30' remaining: api_calls: 1499 proofs: 4 plan: level: basic name: Basic properties: data: type: object properties: id: type: integer example: 1 description: 'Internal user identifier.' name: type: string example: 'API User' description: 'Account display name.' email: type: string example: api-user@example.com description: 'Normalized account email.' email_verified_at: type: string example: '2026-03-30T12:00:00Z' description: 'ISO-8601 timestamp when the account email was verified.' subscriptions: type: array example: - name: default provider: paddle status: active ends_at: null current_period_start: null current_period_end: null description: 'Active subscription rows currently attached to the account, including provider-neutral subscriptions.' items: type: object properties: name: type: string example: default provider: type: string example: paddle status: type: string example: active ends_at: type: string example: null nullable: true current_period_start: type: string example: null nullable: true current_period_end: type: string example: null nullable: true entitlements: type: array example: - product: Basic granted_at: '2026-03-01T00:00:00Z' expires_at: null description: 'Active entitlements currently attached to the account.' items: type: object properties: product: type: string example: Basic granted_at: type: string example: '2026-03-01T00:00:00Z' expires_at: type: string example: null nullable: true current_period: type: object properties: start: type: string example: '2026-03-01' description: 'Start date of the current monthly quota period in `Y-m-d` format.' end: type: string example: '2026-03-31' description: 'End date of the current monthly quota period in `Y-m-d` format.' reset_at: type: string example: '2026-04-01T00:00:00Z' description: 'ISO-8601 timestamp when monthly counters reset.' required: - start - end description: 'Current monthly quota window used for usage and remaining balances.' usage: type: object properties: api_calls: type: integer example: 1 description: 'Successful Rate API lookups consumed in the current monthly period.' proofs: type: integer example: 1 description: 'Proof bundle openings already consumed in the current monthly period.' required: - api_calls - proofs description: 'Current usage counters for the active monthly period.' limits: type: object properties: api_calls: type: integer example: 1500 description: 'Monthly successful Rate API lookup limit from the effective plan.' proofs: type: integer example: 5 description: 'Monthly proof bundle limit from the effective plan.' rpm: type: integer example: 10 description: 'Per-minute request limit from the effective plan.' parallel_streams: type: integer example: 1 description: 'Maximum concurrent rate lookups and proof PDF downloads.' history_years: type: integer example: 1 description: 'Archive depth in calendar years, or null for the full available archive.' nullable: true history_days: type: integer example: 366 description: 'Deprecated compatibility field. Inclusive day count derived from `history_earliest_date`.' history_earliest_date: type: string example: '2025-03-30' description: 'Earliest date allowed by the effective plan and system archive floor.' required: - api_calls - proofs - rpm - parallel_streams - history_years - history_days - history_earliest_date description: 'Effective plan limits currently applied to the account.' remaining: type: object properties: api_calls: type: integer example: 1499 description: 'Remaining monthly Rate API lookups.' proofs: type: integer example: 4 description: 'Remaining monthly proof bundle openings.' required: - api_calls - proofs description: 'Remaining balances for the current monthly period.' plan: type: object properties: level: type: string example: basic description: 'Internal plan level key. Enum: basic, pro, team, enterprise' name: type: string example: Basic description: 'Human-readable plan name.' required: - level - name description: 'Effective plan summary resolved for the authenticated user.' required: - id - name - email - current_period - usage - limits - remaining - plan 401: description: Unauthenticated content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. description: 'Standard Laravel unauthenticated message or system error message.' 429: description: 'RPM throttle' content: application/json: schema: type: object example: error: rate_limit_exceeded message: 'Rate limit exceeded' details: scope: rpm limit: 10 properties: error: type: string example: rate_limit_exceeded description: 'Machine-readable error code for failed requests.' message: type: string example: 'Rate limit exceeded' description: 'Standard Laravel unauthenticated message or system error message.' details: type: object properties: scope: type: string example: rpm description: 'Throttle or diagnostic scope returned for failed requests.' limit: type: integer example: 10 description: 'Active per-minute throttle limit for this user.' 500: description: 'System error' content: application/json: schema: type: object example: error: system_error message: 'Unexpected system error.' details: scope: user_show properties: error: type: string example: system_error description: 'Machine-readable error code for failed requests.' message: type: string example: 'Unexpected system error.' description: 'Standard Laravel unauthenticated message or system error message.' details: type: object properties: scope: type: string example: user_show description: 'Throttle or diagnostic scope returned for failed requests.' tags: - Account /api/v1/tokens: post: summary: 'Create a short-lived Bearer token for protected API calls.' operationId: createAShortLivedBearerTokenForProtectedAPICalls description: '' parameters: [] responses: 201: description: 'Token issued' content: application/json: schema: type: object example: token_type: Bearer access_token: 1|fxproof-example-token expires_at: '2026-03-31T12:00:00Z' expires_in: 86400 user: id: 1 name: 'API User' email: api-user@example.com properties: token_type: type: string example: Bearer description: 'Authentication scheme for the issued token.' access_token: type: string example: 1|fxproof-example-token description: 'Short-lived Sanctum bearer token to send in the Authorization header.' expires_at: type: string example: '2026-03-31T12:00:00Z' description: 'ISO-8601 timestamp when the issued token expires.' expires_in: type: integer example: 86400 description: 'Token lifetime in seconds from the time of issuance.' user: type: object properties: id: type: integer example: 1 description: 'Internal user identifier.' name: type: string example: 'API User' description: 'Account display name.' email: type: string example: api-user@example.com description: 'Normalized account email address.' required: - id - name - email description: 'Summary of the authenticated account tied to the issued token.' required: - token_type - access_token - expires_at - expires_in - user 400: description: 'HTTPS required' content: application/json: schema: type: object example: error: insecure_transport message: 'Token issuance requires HTTPS.' properties: error: type: string example: insecure_transport description: 'Machine-readable error code for failed token requests.' message: type: string example: 'Token issuance requires HTTPS.' description: 'Human-readable status or error message.' 422: description: '' content: application/json: schema: oneOf: - description: 'Validation error' type: object example: error: validation_error message: 'Invalid authentication request.' details: email: - 'The email field must be a valid email address.' device_name: - 'The device name field is required.' properties: error: type: string example: validation_error description: 'Machine-readable error code for failed token requests.' message: type: string example: 'Invalid authentication request.' description: 'Human-readable status or error message.' details: type: object properties: email: type: array example: - 'The email field must be a valid email address.' description: 'Validation messages for the email field.' items: type: string device_name: type: array example: - 'The device name field is required.' description: 'Validation messages for the device_name field.' items: type: string description: 'Validation or throttle metadata for failed requests.' - description: 'Invalid credentials' type: object example: error: invalid_credentials message: 'Invalid credentials.' properties: error: type: string example: invalid_credentials description: 'Machine-readable error code for failed token requests.' message: type: string example: 'Invalid credentials.' description: 'Human-readable status or error message.' 429: description: '' content: application/json: schema: oneOf: - description: 'Authentication throttle' type: object example: error: rate_limit_exceeded message: 'Too many authentication attempts. Please try again later.' details: scope: auth_token_email limit: 5 properties: error: type: string example: rate_limit_exceeded description: 'Machine-readable error code for failed token requests.' message: type: string example: 'Too many authentication attempts. Please try again later.' description: 'Human-readable status or error message.' details: type: object properties: scope: type: string example: auth_token_email description: 'Throttle scope when HTTP 429 is returned. Enum: auth_token_ip, auth_token_email, auth_token_malformed_ip' limit: type: integer example: 5 description: 'Active per-minute throttle limit for this endpoint.' description: 'Validation or throttle metadata for failed requests.' - description: 'Malformed request throttle' type: object example: error: rate_limit_exceeded message: 'Too many invalid authentication requests. Please try again later.' details: scope: auth_token_malformed_ip limit: 5 properties: error: type: string example: rate_limit_exceeded description: 'Machine-readable error code for failed token requests.' message: type: string example: 'Too many invalid authentication requests. Please try again later.' description: 'Human-readable status or error message.' details: type: object properties: scope: type: string example: auth_token_malformed_ip description: 'Throttle scope when HTTP 429 is returned. Enum: auth_token_ip, auth_token_email, auth_token_malformed_ip' limit: type: integer example: 5 description: 'Active per-minute throttle limit for this endpoint.' description: 'Validation or throttle metadata for failed requests.' 500: description: 'System error' content: application/json: schema: type: object example: error: system_error message: 'Unexpected system error.' details: scope: auth_tokens_store properties: error: type: string example: system_error description: 'Machine-readable error code for failed token requests.' message: type: string example: 'Unexpected system error.' description: 'Human-readable status or error message.' details: type: object properties: scope: type: string example: auth_tokens_store description: 'Throttle scope when HTTP 429 is returned. Enum: auth_token_ip, auth_token_email, auth_token_malformed_ip' description: 'Validation or throttle metadata for failed requests.' tags: - Authentication requestBody: required: true content: application/json: schema: type: object properties: email: type: string description: 'Account email. Maximum: 255 characters.' example: api-user@example.com password: type: string description: 'Account password. Maximum: 1024 characters.' example: secret-pass-123 device_name: type: string description: 'Label for this client or integration.' example: 'Production integration' required: - email - password - device_name security: [] /api/v1/proofs: get: summary: 'List proof bundles already opened by the authenticated user.' operationId: listProofBundlesAlreadyOpenedByTheAuthenticatedUser description: '' parameters: - in: query name: dataset description: 'Optional stable public dataset identifier. Maximum: 120 characters. Default: no dataset filter.' example: fed|h10_daily|daily required: false schema: type: string description: 'Optional stable public dataset identifier. Maximum: 120 characters. Default: no dataset filter.' example: fed|h10_daily|daily - in: query name: date description: 'Optional bundle date in `Y-m-d` format. Default: no date filter.' example: '2026-03-30' required: false schema: type: string description: 'Optional bundle date in `Y-m-d` format. Default: no date filter.' example: '2026-03-30' - in: query name: page description: 'Optional page number. Default: 1.' example: 1 required: false schema: type: integer description: 'Optional page number. Default: 1.' example: 1 - in: query name: per_page description: 'Optional items per page. Default: 20. Maximum: 100.' example: 20 required: false schema: type: integer description: 'Optional items per page. Default: 20. Maximum: 100.' example: 20 responses: 200: description: 'Opened bundles' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: data: - id: 16 dataset: fed|h10_daily|daily source: fed source_name: 'Federal Reserve System' product: h10_daily product_name: 'H10 Daily' periodicity: daily periodicity_name: Daily date: '2026-03-30' opened_at: '2026-03-30T10:00:00Z' last_accessed_at: '2026-03-30T10:30:00Z' documents: - id: 019cb777-c5b6-734e-9552-0c4443fab21c name: 'Signed FXProof Proof PDF' type: generated_current_pdf role: proof is_official: false mime_type: application/pdf size_bytes: 24567 source_url: null download_url: 'https://fxproof.org/api/v1/proofs/16/files/019cb777-c5b6-734e-9552-0c4443fab21c' meta: current_page: 1 last_page: 1 per_page: 20 total: 1 properties: data: type: array example: - id: 16 dataset: fed|h10_daily|daily source: fed source_name: 'Federal Reserve System' product: h10_daily product_name: 'H10 Daily' periodicity: daily periodicity_name: Daily date: '2026-03-30' opened_at: '2026-03-30T10:00:00Z' last_accessed_at: '2026-03-30T10:30:00Z' documents: - id: 019cb777-c5b6-734e-9552-0c4443fab21c name: 'Signed FXProof Proof PDF' type: generated_current_pdf role: proof is_official: false mime_type: application/pdf size_bytes: 24567 source_url: null download_url: 'https://fxproof.org/api/v1/proofs/16/files/019cb777-c5b6-734e-9552-0c4443fab21c' items: type: object properties: id: type: integer example: 16 dataset: type: string example: fed|h10_daily|daily source: type: string example: fed source_name: type: string example: 'Federal Reserve System' product: type: string example: h10_daily product_name: type: string example: 'H10 Daily' periodicity: type: string example: daily periodicity_name: type: string example: Daily date: type: string example: '2026-03-30' opened_at: type: string example: '2026-03-30T10:00:00Z' last_accessed_at: type: string example: '2026-03-30T10:30:00Z' documents: type: array example: - id: 019cb777-c5b6-734e-9552-0c4443fab21c name: 'Signed FXProof Proof PDF' type: generated_current_pdf role: proof is_official: false mime_type: application/pdf size_bytes: 24567 source_url: null download_url: 'https://fxproof.org/api/v1/proofs/16/files/019cb777-c5b6-734e-9552-0c4443fab21c' items: type: object properties: id: type: string example: 019cb777-c5b6-734e-9552-0c4443fab21c name: type: string example: 'Signed FXProof Proof PDF' type: type: string example: generated_current_pdf role: type: string example: proof is_official: type: boolean example: false mime_type: type: string example: application/pdf size_bytes: type: integer example: 24567 source_url: type: string example: null nullable: true download_url: type: string example: 'https://fxproof.org/api/v1/proofs/16/files/019cb777-c5b6-734e-9552-0c4443fab21c' meta: type: object properties: current_page: type: integer example: 1 description: 'Current page number.' last_page: type: integer example: 1 description: 'Last available page number.' per_page: type: integer example: 20 description: 'Page size used for this response.' total: type: integer example: 1 description: 'Total number of opened bundles matching the filters.' 401: description: Unauthenticated content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. 422: description: '' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: oneOf: - description: 'Invalid dataset' type: object example: error: invalid_filter message: 'One or more filters are invalid' details: field: dataset value: fed|wrong_code|daily properties: error: type: string example: invalid_filter message: type: string example: 'One or more filters are invalid' details: type: object properties: field: type: string example: dataset value: type: string example: fed|wrong_code|daily - description: 'Invalid request parameters' type: object example: error: validation_error message: 'Invalid request parameters' details: date: - 'The date field must match the format Y-m-d.' properties: error: type: string example: validation_error message: type: string example: 'Invalid request parameters' details: type: object properties: date: type: array example: - 'The date field must match the format Y-m-d.' items: type: string 429: description: 'RPM throttle' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: error: rate_limit_exceeded message: 'Rate limit exceeded' details: scope: rpm limit: 10 properties: error: type: string example: rate_limit_exceeded message: type: string example: 'Rate limit exceeded' details: type: object properties: scope: type: string example: rpm limit: type: integer example: 10 500: description: 'System error' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: error: system_error message: 'Unexpected system error.' details: scope: proofs_index properties: error: type: string example: system_error message: type: string example: 'Unexpected system error.' details: type: object properties: scope: type: string example: proofs_index tags: - 'Proof Bundles' post: summary: 'Open or reuse one proof bundle for one dataset and one date.' operationId: openOrReuseOneProofBundleForOneDatasetAndOneDate description: '' parameters: [] responses: 200: description: 'Existing bundle reused' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: data: id: 16 dataset: fed|h10_daily|daily source: fed source_name: 'Federal Reserve System' product: h10_daily product_name: 'H10 Daily' periodicity: daily periodicity_name: Daily date: '2026-03-30' opened_at: '2026-03-30T10:00:00Z' last_accessed_at: '2026-03-30T10:30:00Z' already_opened: true documents: - id: 019cb777-c5b6-734e-9552-0c4443fab21c name: 'Signed FXProof Proof PDF' type: generated_current_pdf role: proof is_official: false mime_type: application/pdf size_bytes: 24567 source_url: null download_url: 'https://fxproof.org/api/v1/proofs/16/files/019cb777-c5b6-734e-9552-0c4443fab21c' properties: data: type: object properties: id: type: integer example: 16 dataset: type: string example: fed|h10_daily|daily source: type: string example: fed source_name: type: string example: 'Federal Reserve System' product: type: string example: h10_daily product_name: type: string example: 'H10 Daily' periodicity: type: string example: daily periodicity_name: type: string example: Daily date: type: string example: '2026-03-30' opened_at: type: string example: '2026-03-30T10:00:00Z' last_accessed_at: type: string example: '2026-03-30T10:30:00Z' already_opened: type: boolean example: true documents: type: array example: - id: 019cb777-c5b6-734e-9552-0c4443fab21c name: 'Signed FXProof Proof PDF' type: generated_current_pdf role: proof is_official: false mime_type: application/pdf size_bytes: 24567 source_url: null download_url: 'https://fxproof.org/api/v1/proofs/16/files/019cb777-c5b6-734e-9552-0c4443fab21c' items: type: object properties: id: type: string example: 019cb777-c5b6-734e-9552-0c4443fab21c name: type: string example: 'Signed FXProof Proof PDF' type: type: string example: generated_current_pdf role: type: string example: proof is_official: type: boolean example: false mime_type: type: string example: application/pdf size_bytes: type: integer example: 24567 source_url: type: string example: null nullable: true download_url: type: string example: 'https://fxproof.org/api/v1/proofs/16/files/019cb777-c5b6-734e-9552-0c4443fab21c' 201: description: 'New bundle opened' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: data: id: 16 dataset: fed|h10_daily|daily source: fed source_name: 'Federal Reserve System' product: h10_daily product_name: 'H10 Daily' periodicity: daily periodicity_name: Daily date: '2026-03-30' opened_at: '2026-03-30T10:00:00Z' last_accessed_at: '2026-03-30T10:00:00Z' already_opened: false documents: - id: 019cb777-c5b6-734e-9552-0c4443fab21c name: 'Signed FXProof Proof PDF' type: generated_current_pdf role: proof is_official: false mime_type: application/pdf size_bytes: 24567 source_url: null download_url: 'https://fxproof.org/api/v1/proofs/16/files/019cb777-c5b6-734e-9552-0c4443fab21c' properties: data: type: object properties: id: type: integer example: 16 dataset: type: string example: fed|h10_daily|daily source: type: string example: fed source_name: type: string example: 'Federal Reserve System' product: type: string example: h10_daily product_name: type: string example: 'H10 Daily' periodicity: type: string example: daily periodicity_name: type: string example: Daily date: type: string example: '2026-03-30' opened_at: type: string example: '2026-03-30T10:00:00Z' last_accessed_at: type: string example: '2026-03-30T10:00:00Z' already_opened: type: boolean example: false documents: type: array example: - id: 019cb777-c5b6-734e-9552-0c4443fab21c name: 'Signed FXProof Proof PDF' type: generated_current_pdf role: proof is_official: false mime_type: application/pdf size_bytes: 24567 source_url: null download_url: 'https://fxproof.org/api/v1/proofs/16/files/019cb777-c5b6-734e-9552-0c4443fab21c' items: type: object properties: id: type: string example: 019cb777-c5b6-734e-9552-0c4443fab21c name: type: string example: 'Signed FXProof Proof PDF' type: type: string example: generated_current_pdf role: type: string example: proof is_official: type: boolean example: false mime_type: type: string example: application/pdf size_bytes: type: integer example: 24567 source_url: type: string example: null nullable: true download_url: type: string example: 'https://fxproof.org/api/v1/proofs/16/files/019cb777-c5b6-734e-9552-0c4443fab21c' 401: description: Unauthenticated content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. 403: description: '' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: oneOf: - description: 'Source unavailable' type: object example: error: source_unavailable message: 'Source is unavailable' properties: error: type: string example: source_unavailable message: type: string example: 'Source is unavailable' - description: 'Archive window exceeded' type: object example: error: archive_window_exceeded message: "The requested date is outside your plan's archive window." details: requested_date: '2025-12-30' earliest_allowed_date: '2025-12-31' history_years: 1 history_days: 366 properties: error: type: string example: archive_window_exceeded message: type: string example: "The requested date is outside your plan's archive window." details: type: object properties: requested_date: type: string example: '2025-12-30' earliest_allowed_date: type: string example: '2025-12-31' history_years: type: integer example: 1 description: 'Archive depth in calendar years, or null for the full available archive.' nullable: true history_days: type: integer example: 366 404: description: 'Proof not found' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: error: proof_not_found message: 'Proof files not found for the specified criteria' properties: error: type: string example: proof_not_found message: type: string example: 'Proof files not found for the specified criteria' 409: description: 'Proof bundle not ready' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: error: proof_bundle_not_ready message: 'Proof bundle is not ready yet.' properties: error: type: string example: proof_bundle_not_ready message: type: string example: 'Proof bundle is not ready yet.' 422: description: '' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: oneOf: - description: 'Invalid dataset' type: object example: error: invalid_filter message: 'One or more filters are invalid' details: field: dataset value: fed|wrong_code|daily properties: error: type: string example: invalid_filter message: type: string example: 'One or more filters are invalid' details: type: object properties: field: type: string example: dataset value: type: string example: fed|wrong_code|daily - description: 'Invalid request parameters' type: object example: error: validation_error message: 'Invalid request parameters' details: dataset: - 'The dataset field is required.' date: - 'The date field is required.' properties: error: type: string example: validation_error message: type: string example: 'Invalid request parameters' details: type: object properties: dataset: type: array example: - 'The dataset field is required.' items: type: string date: type: array example: - 'The date field is required.' items: type: string 429: description: '' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: oneOf: - description: 'Proof quota exceeded' type: object example: error: proof_limit_exceeded message: 'Proof bundle quota exceeded' properties: error: type: string example: proof_limit_exceeded message: type: string example: 'Proof bundle quota exceeded' - description: 'RPM throttle' type: object example: error: rate_limit_exceeded message: 'Rate limit exceeded' details: scope: rpm limit: 10 properties: error: type: string example: rate_limit_exceeded message: type: string example: 'Rate limit exceeded' details: type: object properties: scope: type: string example: rpm limit: type: integer example: 10 500: description: 'System error' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: error: system_error message: 'Unexpected system error.' details: scope: proofs_store properties: error: type: string example: system_error message: type: string example: 'Unexpected system error.' details: type: object properties: scope: type: string example: proofs_store tags: - 'Proof Bundles' requestBody: required: true content: application/json: schema: type: object properties: dataset: type: string description: 'Stable public dataset identifier. Maximum: 120 characters.' example: fed|h10_daily|daily date: type: string description: 'Requested document date in `Y-m-d` format.' example: '2026-03-30' required: - dataset - date '/api/v1/proofs/{proof}': get: summary: 'Get one previously opened proof bundle.' operationId: getOnePreviouslyOpenedProofBundle description: '' parameters: [] responses: 200: description: 'Bundle detail' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: data: id: 16 dataset: fed|h10_daily|daily source: fed source_name: 'Federal Reserve System' product: h10_daily product_name: 'H10 Daily' periodicity: daily periodicity_name: Daily date: '2026-03-30' opened_at: '2026-03-30T10:00:00Z' last_accessed_at: '2026-03-30T10:30:00Z' documents: - id: 019cb777-c5b6-734e-9552-0c4443fab21c name: 'Signed FXProof Proof PDF' type: generated_current_pdf role: proof is_official: false mime_type: application/pdf size_bytes: 24567 source_url: null download_url: 'https://fxproof.org/api/v1/proofs/16/files/019cb777-c5b6-734e-9552-0c4443fab21c' properties: data: type: object properties: id: type: integer example: 16 dataset: type: string example: fed|h10_daily|daily source: type: string example: fed source_name: type: string example: 'Federal Reserve System' product: type: string example: h10_daily product_name: type: string example: 'H10 Daily' periodicity: type: string example: daily periodicity_name: type: string example: Daily date: type: string example: '2026-03-30' opened_at: type: string example: '2026-03-30T10:00:00Z' last_accessed_at: type: string example: '2026-03-30T10:30:00Z' documents: type: array example: - id: 019cb777-c5b6-734e-9552-0c4443fab21c name: 'Signed FXProof Proof PDF' type: generated_current_pdf role: proof is_official: false mime_type: application/pdf size_bytes: 24567 source_url: null download_url: 'https://fxproof.org/api/v1/proofs/16/files/019cb777-c5b6-734e-9552-0c4443fab21c' items: type: object properties: id: type: string example: 019cb777-c5b6-734e-9552-0c4443fab21c name: type: string example: 'Signed FXProof Proof PDF' type: type: string example: generated_current_pdf role: type: string example: proof is_official: type: boolean example: false mime_type: type: string example: application/pdf size_bytes: type: integer example: 24567 source_url: type: string example: null nullable: true download_url: type: string example: 'https://fxproof.org/api/v1/proofs/16/files/019cb777-c5b6-734e-9552-0c4443fab21c' 401: description: Unauthenticated content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. 404: description: 'Proof access not found' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: error: proof_access_not_found message: 'Proof access not found' properties: error: type: string example: proof_access_not_found message: type: string example: 'Proof access not found' 409: description: 'Proof bundle not ready' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: error: proof_bundle_not_ready message: 'Proof bundle is not ready yet.' properties: error: type: string example: proof_bundle_not_ready message: type: string example: 'Proof bundle is not ready yet.' 429: description: 'RPM throttle' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: error: rate_limit_exceeded message: 'Rate limit exceeded' details: scope: rpm limit: 10 properties: error: type: string example: rate_limit_exceeded message: type: string example: 'Rate limit exceeded' details: type: object properties: scope: type: string example: rpm limit: type: integer example: 10 500: description: 'System error' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: error: system_error message: 'Unexpected system error.' details: scope: proofs_show properties: error: type: string example: system_error message: type: string example: 'Unexpected system error.' details: type: object properties: scope: type: string example: proofs_show tags: - 'Proof Bundles' parameters: - in: path name: proof description: 'Proof access id.' example: 16 required: true schema: type: integer '/api/v1/proofs/{proof}/files/{document}': get: summary: 'Download one file from an opened proof bundle.' operationId: downloadOneFileFromAnOpenedProofBundle description: '' parameters: [] responses: 200: description: 'PDF file stream' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/octet-stream: schema: type: string format: binary 401: description: Unauthenticated content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. 404: description: 'Proof access not found' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: error: proof_access_not_found message: 'Proof file not found for this access' properties: error: type: string example: proof_access_not_found message: type: string example: 'Proof file not found for this access' 409: description: 'Proof bundle not ready' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: error: proof_bundle_not_ready message: 'Proof bundle is not ready yet.' properties: error: type: string example: proof_bundle_not_ready message: type: string example: 'Proof bundle is not ready yet.' 429: description: '' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: oneOf: - description: 'Concurrent operation limit' type: object example: error: rate_limit_exceeded message: 'Too many concurrent data requests.' details: scope: parallel_streams limit: 1 properties: error: type: string example: rate_limit_exceeded message: type: string example: 'Too many concurrent data requests.' details: type: object properties: scope: type: string example: parallel_streams limit: type: integer example: 1 - description: 'RPM throttle' type: object example: error: rate_limit_exceeded message: 'Rate limit exceeded' details: scope: rpm limit: 10 properties: error: type: string example: rate_limit_exceeded message: type: string example: 'Rate limit exceeded' details: type: object properties: scope: type: string example: rpm limit: type: integer example: 10 500: description: 'System error' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: error: system_error message: 'Unexpected system error.' details: scope: proofs_download properties: error: type: string example: system_error message: type: string example: 'Unexpected system error.' details: type: object properties: scope: type: string example: proofs_download 503: description: 'File not available' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: error: file_not_available message: 'Proof file is not available for the selected access.' properties: error: type: string example: file_not_available message: type: string example: 'Proof file is not available for the selected access.' tags: - 'Proof Bundles' parameters: - in: path name: proof description: 'Proof access id.' example: 16 required: true schema: type: integer - in: path name: document description: 'Document id from the bundle manifest.' example: 019cb777-c5b6-734e-9552-0c4443fab21c required: true schema: type: string /api/v1/check-pdf: get: summary: 'Verify a FXProof PDF by document id and payload hash.' operationId: verifyAFXProofPDFByDocumentIdAndPayloadHash description: '' parameters: - in: query name: id description: 'Public document identifier printed in the proof document.' example: doc-id required: true schema: type: string description: 'Public document identifier printed in the proof document.' example: doc-id - in: query name: hash description: 'Payload SHA-256 hash printed in the proof document.' example: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa required: true schema: type: string description: 'Payload SHA-256 hash printed in the proof document.' example: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa responses: 200: description: Verified content: application/json: schema: type: object example: data: verification_status: verified country: USA source_name: 'Federal Reserve System' product: H10_DAILY reference_period: '2026-03-30' rate_frequency: Daily source_url: 'https://example.com/source.pdf' fxproof_document_id: doc-id payload_hash: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa signature_status: unsigned properties: data: type: object properties: verification_status: type: string example: verified description: 'Verification result for a successful match. Enum: verified' country: type: string example: USA description: 'Issuing country inferred from the matched proof metadata when available.' source_name: type: string example: 'Federal Reserve System' description: 'Human-readable source name from the matched proof metadata when available.' product: type: string example: H10_DAILY description: 'Product code stored in the matched proof metadata when available.' reference_period: type: string example: '2026-03-30' description: 'Reference date or period covered by the verified proof.' rate_frequency: type: string example: Daily description: 'Frequency of the rates represented by the proof.' source_url: type: string example: 'https://example.com/source.pdf' description: 'Original source URL attached to the proof when available.' fxproof_document_id: type: string example: doc-id description: 'Public FXProof document identifier embedded in the proof.' payload_hash: type: string example: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa description: 'SHA-256 payload hash embedded in the proof.' signature_status: type: string example: unsigned description: 'Signature status recorded for the proof document.' required: - verification_status 404: description: 'Document not found' content: application/json: schema: type: object example: error: not_found message: 'Document not found' properties: error: type: string example: not_found description: 'Machine-readable error code for validation or verification failure.' message: type: string example: 'Document not found' description: 'Human-readable verification result message.' 422: description: '' content: application/json: schema: oneOf: - description: 'Validation error' type: object example: error: validation_error message: 'Invalid request parameters' details: id: - 'The id field is required.' hash: - 'The hash field is required.' properties: error: type: string example: validation_error description: 'Machine-readable error code for validation or verification failure.' message: type: string example: 'Invalid request parameters' description: 'Human-readable verification result message.' details: type: object properties: id: type: array example: - 'The id field is required.' description: 'Validation messages for the id parameter.' items: type: string hash: type: array example: - 'The hash field is required.' description: 'Validation messages for the hash parameter.' items: type: string description: 'Validation or throttle metadata for failed requests.' - description: 'Hash mismatch' type: object example: error: hash_mismatch message: 'Payload hash does not match' properties: error: type: string example: hash_mismatch description: 'Machine-readable error code for validation or verification failure.' message: type: string example: 'Payload hash does not match' description: 'Human-readable verification result message.' 429: description: 'Verification throttle' content: application/json: schema: type: object example: error: rate_limit_exceeded message: 'Too many verification requests. Please try again later.' details: scope: public_verification limit: 5 properties: error: type: string example: rate_limit_exceeded description: 'Machine-readable error code for validation or verification failure.' message: type: string example: 'Too many verification requests. Please try again later.' description: 'Human-readable verification result message.' details: type: object properties: scope: type: string example: public_verification description: 'Throttle or diagnostic scope returned for failed requests.' limit: type: integer example: 5 description: 'Active per-minute throttle limit for this endpoint.' description: 'Validation or throttle metadata for failed requests.' 500: description: 'System error' content: application/json: schema: type: object example: error: system_error message: 'Unexpected system error.' details: scope: pdf_check_show properties: error: type: string example: system_error description: 'Machine-readable error code for validation or verification failure.' message: type: string example: 'Unexpected system error.' description: 'Human-readable verification result message.' details: type: object properties: scope: type: string example: pdf_check_show description: 'Throttle or diagnostic scope returned for failed requests.' description: 'Validation or throttle metadata for failed requests.' tags: - 'Public Verification' security: [] /api/v1/rates/catalog: get: summary: 'Get the full list of public datasets.' operationId: getTheFullListOfPublicDatasets description: '' parameters: [] responses: 200: description: 'Catalog payload' content: application/json: schema: type: object example: data: datasets: - id: ecb|eurofxref_daily|daily source: ecb source_name: 'European Central Bank' product: eurofxref_daily product_name: 'Euro FX Reference Rates' periodicity: daily periodicity_name: Daily first_available_date: '2026-03-01' latest_available_date: '2026-03-30' bases: - EUR symbols: - GBP - USD proof_available: true properties: data: type: object properties: datasets: type: array example: - id: ecb|eurofxref_daily|daily source: ecb source_name: 'European Central Bank' product: eurofxref_daily product_name: 'Euro FX Reference Rates' periodicity: daily periodicity_name: Daily first_available_date: '2026-03-01' latest_available_date: '2026-03-30' bases: - EUR symbols: - GBP - USD proof_available: true description: 'Flat list of active dataset definitions discovered from stored rates.' items: type: object properties: id: type: string example: ecb|eurofxref_daily|daily source: type: string example: ecb source_name: type: string example: 'European Central Bank' product: type: string example: eurofxref_daily product_name: type: string example: 'Euro FX Reference Rates' periodicity: type: string example: daily periodicity_name: type: string example: Daily first_available_date: type: string example: '2026-03-01' latest_available_date: type: string example: '2026-03-30' bases: type: array example: - EUR items: type: string symbols: type: array example: - GBP - USD items: type: string proof_available: type: boolean example: true tags: - Rates /api/v1/rates: get: summary: 'Get exchange rates for one dataset.' operationId: getExchangeRatesForOneDataset description: '' parameters: - in: query name: dataset description: 'Dataset id from `/api/v1/rates/catalog`. Maximum: 120 characters.' example: ecb|eurofxref_daily|daily required: true schema: type: string description: 'Dataset id from `/api/v1/rates/catalog`. Maximum: 120 characters.' example: ecb|eurofxref_daily|daily - in: query name: date description: 'Optional rate date in `Y-m-d` format. Default: latest date allowed by the effective archive window. If `base` is sent, the latest allowed date is resolved inside that base.' example: '2026-03-30' required: false schema: type: string description: 'Optional rate date in `Y-m-d` format. Default: latest date allowed by the effective archive window. If `base` is sent, the latest allowed date is resolved inside that base.' example: '2026-03-30' - in: query name: base description: 'Optional 3-letter base currency code. Default: auto-select when one base exists for the selected date; return `409 ambiguous_data` when more than one base exists.' example: EUR required: false schema: type: string description: 'Optional 3-letter base currency code. Default: auto-select when one base exists for the selected date; return `409 ambiguous_data` when more than one base exists.' example: EUR - in: query name: symbols description: 'Optional comma-separated quote currency filter. Maximum: 1024 characters and 128 values. Default: all available quote currencies for the selected dataset, date, and base. The full set must be valid for the selected dataset and base.' example: 'USD,GBP,KZT' required: false schema: type: string description: 'Optional comma-separated quote currency filter. Maximum: 1024 characters and 128 values. Default: all available quote currencies for the selected dataset, date, and base. The full set must be valid for the selected dataset and base.' example: 'USD,GBP,KZT' responses: 200: description: 'Rates payload' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: dataset: ecb|eurofxref_daily|daily source: ecb product: eurofxref_daily periodicity: daily date: '2026-03-30' base: EUR rates: GBP: 0.8561 USD: 1.0825 meta: cached: false signature: 'sha256:example-signature' properties: dataset: type: string example: ecb|eurofxref_daily|daily description: 'Stable public dataset identifier resolved for this response.' source: type: string example: ecb description: 'Source code that owns the dataset.' product: type: string example: eurofxref_daily description: 'Product code that owns the dataset.' periodicity: type: string example: daily description: 'Periodicity code that owns the dataset.' date: type: string example: '2026-03-30' description: 'Actual rate date used for this response. If the request omits `date`, this is the latest allowed date for the dataset or selected base scope.' base: type: string example: EUR description: 'Base currency used by the response payload.' rates: type: object properties: GBP: type: number example: 0.8561 USD: type: number example: 1.0825 description: 'Quote map keyed by ISO currency symbol.' meta: type: object properties: cached: type: boolean example: false description: 'Whether the response body came from the application cache.' signature: type: string example: 'sha256:example-signature' description: 'Deterministic SHA-256 signature of the returned `rates` object.' 401: description: Unauthenticated content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. description: 'Human-readable status or failure message.' 403: description: '' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: oneOf: - description: 'Source unavailable' type: object example: error: source_unavailable message: 'Source is unavailable' properties: error: type: string example: source_unavailable description: 'Machine-readable error code for failed requests.' message: type: string example: 'Source is unavailable' description: 'Human-readable status or failure message.' - description: 'Archive window exceeded' type: object example: error: archive_window_exceeded message: "The requested date is outside your plan's archive window." details: requested_date: '2025-12-30' earliest_allowed_date: '2025-12-31' history_years: 1 history_days: 366 properties: error: type: string example: archive_window_exceeded description: 'Machine-readable error code for failed requests.' message: type: string example: "The requested date is outside your plan's archive window." description: 'Human-readable status or failure message.' details: type: object properties: requested_date: type: string example: '2025-12-30' description: 'Date rejected by the effective archive window.' earliest_allowed_date: type: string example: '2025-12-31' description: 'Earliest date allowed by the effective plan and system archive floor.' history_years: type: integer example: 1 description: 'Archive depth in calendar years, or null for the full available archive.' nullable: true history_days: type: integer example: 366 description: 'Deprecated compatibility field. Inclusive day count derived from `earliest_allowed_date`.' description: 'Validation, filter, throttle, or diagnostic metadata for failed requests.' 404: description: 'No data' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: error: no_data message: 'No rates found for the specified criteria' available_dates: previous: '2026-03-29' next: '2026-03-31' latest: '2026-03-31' properties: error: type: string example: no_data description: 'Machine-readable error code for failed requests.' message: type: string example: 'No rates found for the specified criteria' description: 'Human-readable status or failure message.' available_dates: type: object properties: previous: type: string example: '2026-03-29' description: 'Nearest earlier date with matching data.' next: type: string example: '2026-03-31' description: 'Nearest later date with matching data.' latest: type: string example: '2026-03-31' description: 'Latest known date with matching data.' 409: description: 'Ambiguous base' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: error: ambiguous_data message: 'Base currency is required for this dataset on the requested date' details: available_bases: - EUR - USD properties: error: type: string example: ambiguous_data description: 'Machine-readable error code for failed requests.' message: type: string example: 'Base currency is required for this dataset on the requested date' description: 'Human-readable status or failure message.' details: type: object properties: available_bases: type: array example: - EUR - USD description: 'Available bases on the requested date when `base` is required.' items: type: string description: 'Validation, filter, throttle, or diagnostic metadata for failed requests.' 422: description: '' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: oneOf: - description: 'Validation error' type: object example: error: validation_error message: 'Invalid request parameters' details: dataset: - 'The dataset field is required.' date: - 'The date field must match the format Y-m-d.' properties: error: type: string example: validation_error description: 'Machine-readable error code for failed requests.' message: type: string example: 'Invalid request parameters' description: 'Human-readable status or failure message.' details: type: object properties: dataset: type: array example: - 'The dataset field is required.' items: type: string date: type: array example: - 'The date field must match the format Y-m-d.' items: type: string description: 'Validation, filter, throttle, or diagnostic metadata for failed requests.' - description: 'Invalid filter' type: object example: error: invalid_filter message: 'One or more filters are invalid' details: field: base value: ZZZ properties: error: type: string example: invalid_filter description: 'Machine-readable error code for failed requests.' message: type: string example: 'One or more filters are invalid' description: 'Human-readable status or failure message.' details: type: object properties: field: type: string example: base description: 'Invalid filter field name when `invalid_filter` is returned.' value: type: string example: ZZZ description: 'Rejected filter value when `invalid_filter` is returned.' description: 'Validation, filter, throttle, or diagnostic metadata for failed requests.' 429: description: '' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: oneOf: - description: 'Monthly Rate API lookup quota exceeded' type: object example: error: rate_limit_exceeded message: 'Rate API lookup quota exceeded' details: scope: user limit: 1500 properties: error: type: string example: rate_limit_exceeded description: 'Machine-readable error code for failed requests.' message: type: string example: 'Rate API lookup quota exceeded' description: 'Human-readable status or failure message.' details: type: object properties: scope: type: string example: user description: 'Throttle or diagnostic scope returned for failed requests.' limit: type: integer example: 1500 description: 'Active quota or per-minute limit associated with the failure.' description: 'Validation, filter, throttle, or diagnostic metadata for failed requests.' - description: 'Concurrent operation limit' type: object example: error: rate_limit_exceeded message: 'Too many concurrent data requests.' details: scope: parallel_streams limit: 1 properties: error: type: string example: rate_limit_exceeded description: 'Machine-readable error code for failed requests.' message: type: string example: 'Too many concurrent data requests.' description: 'Human-readable status or failure message.' details: type: object properties: scope: type: string example: parallel_streams description: 'Throttle or diagnostic scope returned for failed requests.' limit: type: integer example: 1 description: 'Active quota or per-minute limit associated with the failure.' description: 'Validation, filter, throttle, or diagnostic metadata for failed requests.' - description: 'RPM throttle' type: object example: error: rate_limit_exceeded message: 'Rate limit exceeded' details: scope: rpm limit: 10 properties: error: type: string example: rate_limit_exceeded description: 'Machine-readable error code for failed requests.' message: type: string example: 'Rate limit exceeded' description: 'Human-readable status or failure message.' details: type: object properties: scope: type: string example: rpm description: 'Throttle or diagnostic scope returned for failed requests.' limit: type: integer example: 10 description: 'Active quota or per-minute limit associated with the failure.' description: 'Validation, filter, throttle, or diagnostic metadata for failed requests.' 500: description: 'System error' headers: X-Quota-Limit: description: 'Monthly quota limit for this endpoint scope.' schema: type: integer example: 1500 X-Quota-Remaining: description: 'Remaining monthly quota for this endpoint scope after this response.' schema: type: integer example: 1499 X-Quota-Reset: description: 'Seconds until the monthly quota period resets.' schema: type: integer example: 2592000 content: application/json: schema: type: object example: error: system_error message: 'Unexpected system error.' details: scope: rates_index properties: error: type: string example: system_error description: 'Machine-readable error code for failed requests.' message: type: string example: 'Unexpected system error.' description: 'Human-readable status or failure message.' details: type: object properties: scope: type: string example: rates_index description: 'Throttle or diagnostic scope returned for failed requests.' description: 'Validation, filter, throttle, or diagnostic metadata for failed requests.' tags: - Rates /api/health: get: summary: 'Return a small public health payload.' operationId: returnASmallPublicHealthPayload description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: status: healthy version: 1.0.0 timestamp: '2026-07-17T20:12:56.004444Z' properties: status: type: string example: healthy description: 'Public health status of the API. Enum: healthy' version: type: string example: 1.0.0 description: 'Current public API version string.' timestamp: type: string example: '2026-07-17T20:12:56.004444Z' description: 'ISO-8601 timestamp when the health payload was generated.' required: - status - version - timestamp 429: description: 'Health check throttle' content: application/json: schema: type: object example: error: rate_limit_exceeded message: 'Too many health check requests. Please try again later.' details: scope: health limit: 60 properties: error: type: string example: rate_limit_exceeded description: 'Machine-readable error code when the endpoint is throttled.' message: type: string example: 'Too many health check requests. Please try again later.' description: 'Human-readable status or throttle message.' details: type: object properties: scope: type: string example: health description: 'Throttle scope when HTTP 429 is returned. Enum: health' limit: type: integer example: 60 description: 'Active per-minute throttle limit for this endpoint.' tags: - System security: []