{"openapi":"3.1.0","info":{"title":"Bullion API","version":"1.0.0","summary":"Gold spot prices as a simple JSON REST API.","description":"Live and historical gold prices in 30 currencies. Responses are served from a cache refreshed hourly by a scheduled job; API requests never call upstream providers. Authenticate price-data requests with the canonical and preferred X-API-Key header, or use the api_key query parameter as a fallback when a client cannot set custom headers. Query credentials may appear in browser history, copied URLs, referrers, intermediary infrastructure, and logs. Query authentication does not enable cross-origin browser fetch; CORS remains separate. If both transports are supplied, they must match; differing values return HTTP 401 with code conflicting_credentials. Free and Pro are for non-commercial use only. Enterprise includes commercial display and integration. Raw or substantially equivalent data redistribution and resale are excluded from all standard plans.","termsOfService":"https://bullionapi.dev/terms","contact":{"name":"Bullion API","url":"https://bullionapi.dev","email":"hello@bullionapi.dev"}},"servers":[{"url":"https://api.bullionapi.dev"}],"security":[{"ApiKeyAuth":[]},{"ApiKeyQuery":[]}],"tags":[{"name":"prices","description":"Gold price data (API key required)"},{"name":"macro","description":"Latest macroeconomic observations (API key required)"},{"name":"reserves","description":"Pro and Enterprise annual central-bank reserve data"},{"name":"account","description":"Account-scoped usage (session cookie)"},{"name":"meta","description":"Service metadata (public)"}],"paths":{"/v1/latest":{"get":{"tags":["prices"],"security":[{"ApiKeyAuth":[]},{"ApiKeyQuery":[]}],"summary":"Latest gold spot price","description":"Returns the most recent gold spot price and the FX rates needed to convert it into the requested base currency. Prices default to troy ounces. Pass unit=gram, unit=kilogram, or unit=troy_oz (including their documented aliases) to choose the response unit. Cached for 1 hour. Usage increments after API-key and quota checks but before endpoint validation.","operationId":"getLatest","parameters":[{"$ref":"#/components/parameters/Currency"},{"$ref":"#/components/parameters/Unit"}],"responses":{"200":{"description":"Latest prices, served from cache.","headers":{"x-ratelimit-limit":{"description":"Your plan's monthly request cap.","schema":{"type":"integer","example":30}},"x-ratelimit-used":{"description":"Requests used this month, including this one.","schema":{"type":"integer","example":1}},"x-ratelimit-remaining":{"description":"Requests remaining this month.","schema":{"type":"integer","example":29}},"x-ratelimit-plan":{"description":"The plan the quota is enforced against.","schema":{"type":"string","enum":["free","pro","enterprise"],"example":"free"}},"x-ratelimit-reset":{"description":"When the quota resets (1st of next month, 00:00 UTC).","schema":{"type":"string","format":"date-time"}},"X-API-CURRENT":{"description":"Compatibility alias for x-ratelimit-used.","schema":{"type":"integer","example":1}},"X-API-QUOTA":{"description":"Compatibility alias for x-ratelimit-limit.","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LatestResponse"}}}},"400":{"description":"The requested unit is not supported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LatestBadRequestError"},"example":{"status":"error","error":{"code":"invalid_unit","message":"unit must be one of: gram, g, kilogram, kg, troy_oz, toz"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/EmailNotVerified"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"tags":["prices"],"summary":"Not supported — read-only API","operationId":"postLatestNotAllowed","responses":{"405":{"$ref":"#/components/responses/MethodNotAllowed"}}}},"/v1/timeseries":{"get":{"tags":["prices"],"security":[{"ApiKeyAuth":[]},{"ApiKeyQuery":[]}],"summary":"Historical daily gold closes","description":"Returns daily gold closes across a date range. Only cached dates are included in `rates`; scheduled refresh and backfill jobs populate the cache. Prices default to troy ounces; pass unit=gram, unit=kilogram, or unit=troy_oz (including their documented aliases) to choose the response unit.","operationId":"getTimeseries","parameters":[{"$ref":"#/components/parameters/Currency"},{"$ref":"#/components/parameters/StartDate"},{"$ref":"#/components/parameters/EndDate"},{"$ref":"#/components/parameters/Unit"}],"responses":{"200":{"description":"Daily closes keyed by date. Dates with no cached row are omitted.","headers":{"x-ratelimit-limit":{"description":"Your plan's monthly request cap.","schema":{"type":"integer","example":30}},"x-ratelimit-used":{"description":"Requests used this month, including this one.","schema":{"type":"integer","example":1}},"x-ratelimit-remaining":{"description":"Requests remaining this month.","schema":{"type":"integer","example":29}},"x-ratelimit-plan":{"description":"The plan the quota is enforced against.","schema":{"type":"string","enum":["free","pro","enterprise"],"example":"free"}},"x-ratelimit-reset":{"description":"When the quota resets (1st of next month, 00:00 UTC).","schema":{"type":"string","format":"date-time"}},"X-API-CURRENT":{"description":"Compatibility alias for x-ratelimit-used.","schema":{"type":"integer","example":1}},"X-API-QUOTA":{"description":"Compatibility alias for x-ratelimit-limit.","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeseriesResponse"}}}},"400":{"description":"Invalid date, range, or unit query parameter.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeseriesBadRequestError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/EmailNotVerified"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/rates/{region}":{"get":{"tags":["macro"],"security":[{"ApiKeyAuth":[]},{"ApiKeyQuery":[]}],"summary":"Latest stored US macro rates","description":"Returns the latest stored policy, yield, and inflation observation for each available series in the requested region. Policy rates, monthly yield averages, breakevens, and CPI can have independent observation periods. Every observation includes its upstream series ID and source attribution. U.S. Treasury yields use valid daily observations from complete calendar months; breakevens use matched nominal and real dates; BLS CPI-U is the not-seasonally-adjusted CUUR0000SA0 series. Free, Pro, and Enterprise keys receive the same data contract; only their existing monthly quota limits differ. API requests read the database and never call upstream sources.","operationId":"getMacroRates","parameters":[{"$ref":"#/components/parameters/MacroRegion"}],"responses":{"200":{"description":"Latest policy, yield, and inflation observations with per-observation provenance.","headers":{"x-ratelimit-limit":{"description":"Your plan's monthly request cap.","schema":{"type":"integer","example":30}},"x-ratelimit-used":{"description":"Requests used this month, including this one.","schema":{"type":"integer","example":1}},"x-ratelimit-remaining":{"description":"Requests remaining this month.","schema":{"type":"integer","example":29}},"x-ratelimit-plan":{"description":"The plan the quota is enforced against.","schema":{"type":"string","enum":["free","pro","enterprise"],"example":"free"}},"x-ratelimit-reset":{"description":"When the quota resets (1st of next month, 00:00 UTC).","schema":{"type":"string","format":"date-time"}},"X-API-CURRENT":{"description":"Compatibility alias for x-ratelimit-used.","schema":{"type":"integer","example":1}},"X-API-QUOTA":{"description":"Compatibility alias for x-ratelimit-limit.","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MacroRatesResponse"}}}},"400":{"description":"The requested macro region is not supported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MacroBadRequestError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/EmailNotVerified"},"429":{"$ref":"#/components/responses/QuotaExceeded"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"description":"No stored observations are available for the requested region.","headers":{"x-ratelimit-limit":{"description":"Your plan's monthly request cap.","schema":{"type":"integer","example":30}},"x-ratelimit-used":{"description":"Requests used this month, including this one.","schema":{"type":"integer","example":1}},"x-ratelimit-remaining":{"description":"Requests remaining this month.","schema":{"type":"integer","example":29}},"x-ratelimit-plan":{"description":"The plan the quota is enforced against.","schema":{"type":"string","enum":["free","pro","enterprise"],"example":"free"}},"x-ratelimit-reset":{"description":"When the quota resets (1st of next month, 00:00 UTC).","schema":{"type":"string","format":"date-time"}},"X-API-CURRENT":{"description":"Compatibility alias for x-ratelimit-used.","schema":{"type":"integer","example":1}},"X-API-QUOTA":{"description":"Compatibility alias for x-ratelimit-limit.","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"tags":["macro"],"summary":"Not supported — read-only API","operationId":"postMacroRatesNotAllowed","responses":{"405":{"$ref":"#/components/responses/MethodNotAllowed"}}}},"/v1/central-bank-reserves":{"get":{"tags":["reserves"],"security":[{"ApiKeyAuth":[]},{"ApiKeyQuery":[]}],"summary":"Annual central-bank reserve values and gold share","description":"Annual reserve valuations for Pro and Enterprise accounts from World Bank, World Development Indicators, whose underlying provider is International Monetary Fund, International Financial Statistics. Bullion API derives gold reserve value, gold share, and consecutive-year value change from cached observations. Annual value change combines holdings changes, gold-price movement, and revisions; it does not measure tonnes bought or sold.","operationId":"getCentralBankReserves","parameters":[{"$ref":"#/components/parameters/CountryIso2"},{"$ref":"#/components/parameters/StartYear"},{"$ref":"#/components/parameters/EndYear"}],"responses":{"200":{"description":"Complete annual reserve observations served from the automated cache.","headers":{"x-ratelimit-limit":{"description":"Your plan's monthly request cap.","schema":{"type":"integer","example":30}},"x-ratelimit-used":{"description":"Requests used this month, including this one.","schema":{"type":"integer","example":1}},"x-ratelimit-remaining":{"description":"Requests remaining this month.","schema":{"type":"integer","example":29}},"x-ratelimit-plan":{"description":"The plan the quota is enforced against.","schema":{"type":"string","enum":["free","pro","enterprise"],"example":"free"}},"x-ratelimit-reset":{"description":"When the quota resets (1st of next month, 00:00 UTC).","schema":{"type":"string","format":"date-time"}},"X-API-CURRENT":{"description":"Compatibility alias for x-ratelimit-used.","schema":{"type":"integer","example":1}},"X-API-QUOTA":{"description":"Compatibility alias for x-ratelimit-limit.","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CentralBankReservesResponse"}}}},"400":{"description":"Invalid country or year parameters. The request still consumes quota.","headers":{"x-ratelimit-limit":{"description":"Your plan's monthly request cap.","schema":{"type":"integer","example":30}},"x-ratelimit-used":{"description":"Requests used this month, including this one.","schema":{"type":"integer","example":1}},"x-ratelimit-remaining":{"description":"Requests remaining this month.","schema":{"type":"integer","example":29}},"x-ratelimit-plan":{"description":"The plan the quota is enforced against.","schema":{"type":"string","enum":["free","pro","enterprise"],"example":"free"}},"x-ratelimit-reset":{"description":"When the quota resets (1st of next month, 00:00 UTC).","schema":{"type":"string","format":"date-time"}},"X-API-CURRENT":{"description":"Compatibility alias for x-ratelimit-used.","schema":{"type":"integer","example":1}},"X-API-QUOTA":{"description":"Compatibility alias for x-ratelimit-limit.","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CentralBankBadRequestError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Email verification is required, followed by an active Pro or Enterprise plan.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/EmailNotVerifiedError"},{"$ref":"#/components/schemas/PlanRequiredError"}]},"examples":{"email_not_verified":{"value":{"status":"error","error":{"code":"email_not_verified","message":"Verify your email address before using the API"}}},"plan_required":{"value":{"status":"error","error":{"code":"plan_required","message":"This endpoint requires one of these plans: pro, enterprise","required_plans":["pro","enterprise"],"plan":"free"}}}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"description":"The automated cache has no complete observations.","headers":{"x-ratelimit-limit":{"description":"Your plan's monthly request cap.","schema":{"type":"integer","example":30}},"x-ratelimit-used":{"description":"Requests used this month, including this one.","schema":{"type":"integer","example":1}},"x-ratelimit-remaining":{"description":"Requests remaining this month.","schema":{"type":"integer","example":29}},"x-ratelimit-plan":{"description":"The plan the quota is enforced against.","schema":{"type":"string","enum":["free","pro","enterprise"],"example":"free"}},"x-ratelimit-reset":{"description":"When the quota resets (1st of next month, 00:00 UTC).","schema":{"type":"string","format":"date-time"}},"X-API-CURRENT":{"description":"Compatibility alias for x-ratelimit-used.","schema":{"type":"integer","example":1}},"X-API-QUOTA":{"description":"Compatibility alias for x-ratelimit-limit.","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"data_unavailable","message":"Central-bank reserve data is not available"}}}}}}},"post":{"tags":["reserves"],"summary":"Not supported — read-only API","operationId":"postCentralBankReservesNotAllowed","responses":{"405":{"$ref":"#/components/responses/MethodNotAllowed"}}}},"/v1/usage":{"get":{"tags":["account"],"summary":"Plan, quota and recent requests for the signed-in user","description":"Authenticated via session cookie (NOT X-API-Key) so the dashboard can call it directly without storing an API key client-side. This spec is informational for this endpoint: browsers obtain the cookie by signing in at https://bullionapi.dev/login.","operationId":"getUsage","security":[{"CookieAuth":[]}],"responses":{"200":{"description":"Current plan, monthly quota state and the 50 most recent requests.","headers":{"x-ratelimit-limit":{"description":"Your plan's monthly request cap.","schema":{"type":"integer","example":30}},"x-ratelimit-used":{"description":"Requests used this month, including this one.","schema":{"type":"integer","example":1}},"x-ratelimit-remaining":{"description":"Requests remaining this month.","schema":{"type":"integer","example":29}},"x-ratelimit-plan":{"description":"The plan the quota is enforced against.","schema":{"type":"string","enum":["free","pro","enterprise"],"example":"free"}},"x-ratelimit-reset":{"description":"When the quota resets (1st of next month, 00:00 UTC).","schema":{"type":"string","format":"date-time"}},"X-API-CURRENT":{"description":"Compatibility alias for x-ratelimit-used.","schema":{"type":"integer","example":1}},"X-API-QUOTA":{"description":"Compatibility alias for x-ratelimit-limit.","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageResponse"}}}},"401":{"description":"Not signed in.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"unauthenticated","message":"Not signed in"}}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/health":{"get":{"tags":["meta"],"summary":"Service health","description":"Public, no auth. Reports database reachability and cache freshness. Returns 503 when the cache has not been refreshed within the staleness budget.","operationId":"getHealth","security":[],"responses":{"200":{"description":"Healthy: database reachable and cache fresh.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"503":{"description":"Degraded: database unreachable or cache stale.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key created in the dashboard, prefixed `bullion_`."},"ApiKeyQuery":{"type":"apiKey","in":"query","name":"api_key","description":"Fallback API key for clients that cannot set custom headers. Query credentials can be exposed by URLs; prefer ApiKeyAuth whenever possible."},"CookieAuth":{"type":"apiKey","in":"cookie","name":"better-auth.session_token","description":"Session cookie set on sign-in. Over HTTPS the name is prefixed: `__Secure-better-auth.session_token`."}},"parameters":{"Currency":{"name":"currency","in":"query","required":false,"schema":{"type":"string","default":"USD","example":"EUR"},"description":"ISO 4217 base currency, case-insensitive. Supported: USD, EUR, GBP, JPY, CHF, CAD, AUD, NZD, CNY, HKD, SGD, SEK, NOK, DKK, PLN, CZK, HUF, TRY, ZAR, INR, KRW, BRL, MXN, AED, SAR, ILS, THB, IDR, MYR, PHP. Any other code is accepted and returns 200 with empty `metals` / `currencies` maps until that currency is seeded."},"Unit":{"name":"unit","in":"query","required":false,"schema":{"type":"string","enum":["gram","g","kilogram","kg","troy_oz","toz"],"default":"toz"},"description":"Output mass unit. Omit or leave empty for the legacy toz response. gram and g return grams; kilogram and kg return kilograms; troy_oz and toz return troy ounces. Values are converted to eight decimal places. Other non-empty values return 400 invalid_unit."},"StartDate":{"name":"start_date","in":"query","required":true,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","example":"2026-01-01"},"description":"First day to include (inclusive), YYYY-MM-DD."},"EndDate":{"name":"end_date","in":"query","required":true,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","example":"2026-01-31"},"description":"Last day to include (inclusive), YYYY-MM-DD. Must be >= start_date."},"CountryIso2":{"name":"country","in":"query","required":false,"schema":{"type":"string","pattern":"^[A-Za-z]{2}$","example":"GB"},"description":"ISO 3166-1 alpha-2 country code, case-insensitive."},"StartYear":{"name":"start","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}$","example":"2020"},"description":"First observation year to include (inclusive)."},"EndYear":{"name":"end","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}$","example":"2025"},"description":"Last observation year to include (inclusive). Must be >= start."},"MacroRegion":{"name":"region","in":"path","required":true,"schema":{"type":"string","enum":["us"],"example":"us"},"description":"Macro region. US policy rates are available in this release."}},"responses":{"Unauthorized":{"description":"Missing, conflicting, or invalid API key credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"examples":{"missing":{"value":{"status":"error","error":{"code":"missing_api_key","message":"Missing API key"}}},"conflict":{"value":{"status":"error","error":{"code":"conflicting_credentials","message":"Conflicting API key credentials"}}},"invalid":{"value":{"status":"error","error":{"code":"invalid_api_key","message":"Invalid or revoked API key"}}}}}}},"EmailNotVerified":{"description":"The API-key owner must verify their email address before accessing price data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"email_not_verified","message":"Verify your email address before using the API"}}}}},"QuotaExceeded":{"description":"Monthly quota reached. Quota resets on the 1st of next month, 00:00 UTC.","headers":{"x-ratelimit-limit":{"description":"Your plan's monthly request cap.","schema":{"type":"integer","example":30}},"x-ratelimit-used":{"description":"Requests used this month, including this one.","schema":{"type":"integer","example":1}},"x-ratelimit-remaining":{"description":"Requests remaining this month.","schema":{"type":"integer","example":29}},"x-ratelimit-plan":{"description":"The plan the quota is enforced against.","schema":{"type":"string","enum":["free","pro","enterprise"],"example":"free"}},"x-ratelimit-reset":{"description":"When the quota resets (1st of next month, 00:00 UTC).","schema":{"type":"string","format":"date-time"}},"X-API-CURRENT":{"description":"Compatibility alias for x-ratelimit-used.","schema":{"type":"integer","example":1}},"X-API-QUOTA":{"description":"Compatibility alias for x-ratelimit-limit.","schema":{"type":"integer","example":30}},"retry-after":{"description":"Seconds until the quota resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaExceededError"},"example":{"status":"error","error":{"code":"quota_exceeded","message":"Your monthly usage limit has been reached. Please upgrade your subscription plan.","plan":"free","used":30,"limit":30,"reset_at":"2026-08-01T00:00:00.000Z"}}}}},"TooManyRequests":{"description":"The API-key rolling window or monthly quota has been exceeded.","headers":{"x-ratelimit-limit":{"description":"Your plan's monthly request cap.","schema":{"type":"integer","example":30}},"x-ratelimit-used":{"description":"Requests used this month, including this one.","schema":{"type":"integer","example":1}},"x-ratelimit-remaining":{"description":"Requests remaining this month.","schema":{"type":"integer","example":29}},"x-ratelimit-plan":{"description":"The plan the quota is enforced against.","schema":{"type":"string","enum":["free","pro","enterprise"],"example":"free"}},"x-ratelimit-reset":{"description":"When the quota resets (1st of next month, 00:00 UTC).","schema":{"type":"string","format":"date-time"}},"X-API-CURRENT":{"description":"Compatibility alias for x-ratelimit-used.","schema":{"type":"integer","example":1}},"X-API-QUOTA":{"description":"Compatibility alias for x-ratelimit-limit.","schema":{"type":"integer","example":30}},"retry-after":{"description":"Seconds until the applicable limit resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/QuotaExceededError"},{"$ref":"#/components/schemas/RateLimitedError"}]},"examples":{"rate_limited":{"value":{"status":"error","error":{"code":"rate_limited","message":"Rate limit exceeded"}}},"quota_exceeded":{"value":{"status":"error","error":{"code":"quota_exceeded","message":"Your monthly usage limit has been reached. Please upgrade your subscription plan."}}}}}}},"MethodNotAllowed":{"description":"The API is read-only; writes are not supported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"method_not_allowed","message":"Method not allowed"}}}}},"InternalError":{"description":"Server configuration error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"config_error","message":"DATABASE_URL not set"}}}}}},"schemas":{"LatestResponse":{"type":"object","required":["status","currency","unit","metals","currencies","timestamps"],"properties":{"status":{"type":"string","const":"success"},"currency":{"type":"string","description":"Base currency of the response."},"unit":{"type":"string","enum":["toz","troy_oz","gram","kilogram"],"description":"Normalized output mass unit. Legacy default is `toz`; explicit troy-ounce requests return `troy_oz`."},"metals":{"type":"object","additionalProperties":{"type":"number"},"description":"Spot prices keyed by metal. Gold only at launch: `{ \"gold\": 4527.86 }`.","example":{"gold":4527.86}},"currencies":{"type":"object","additionalProperties":{"type":"number"},"description":"FX rates from the base currency keyed by target currency.","example":{"EUR":0.9134,"GBP":0.7783,"JPY":154.22,"CAD":1.3715}},"timestamps":{"type":"object","required":["metal","currency"],"properties":{"metal":{"type":"string","description":"ISO 8601 fetch time of the metal price, or empty string if unseeded."},"currency":{"type":"string","description":"ISO 8601 fetch time of the FX rates, or empty string if unseeded."}}}}},"TimeseriesResponse":{"type":"object","required":["status","currency","unit","start_date","end_date","rates"],"properties":{"status":{"type":"string","const":"success"},"currency":{"type":"string"},"unit":{"type":"string","enum":["toz","troy_oz","gram","kilogram"],"description":"Normalized output mass unit. Omitted or empty input returns legacy `toz`."},"start_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"end_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"rates":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/TimeseriesDay"},"description":"Daily closes keyed by YYYY-MM-DD. Only cached dates are present."}}},"TimeseriesDay":{"type":"object","required":["currencies","date","metals"],"properties":{"currencies":{"type":"object","additionalProperties":{"type":"number"},"example":{"EUR":0.9134,"GBP":0.7783}},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"metals":{"type":"object","additionalProperties":{"type":"number"},"example":{"gold":3320.1}}}},"MacroRatesResponse":{"type":"object","required":["status","region","policy","yields","inflation"],"properties":{"status":{"type":"string","const":"success"},"region":{"type":"string","const":"us"},"policy":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/MacroRateObservation"}},"yields":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/MacroRateObservation"}},"inflation":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/MacroRateObservation"}}}},"MacroRateObservation":{"type":"object","required":["series_id","value","unit","observation_period","method","source_series_id","source_id","attribution","fetched_at"],"properties":{"series_id":{"type":"string"},"value":{"type":"number"},"unit":{"type":"string","example":"percent"},"observation_period":{"type":"string","format":"date"},"method":{"type":"string","enum":["latest","monthly_average","month_end","derived_monthly_average"]},"source_series_id":{"type":"string"},"source_id":{"type":"string"},"attribution":{"type":"string"},"fetched_at":{"type":"string","format":"date-time"}}},"MacroBadRequestError":{"type":"object","additionalProperties":false,"required":["status","error"],"properties":{"status":{"type":"string","const":"error"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["invalid_region"]},"message":{"type":"string"}}}}},"CentralBankReservesResponse":{"type":"object","required":["status","source","methodology","coverage","reserves"],"properties":{"status":{"type":"string","const":"success"},"source":{"$ref":"#/components/schemas/CentralBankReserveSource"},"methodology":{"$ref":"#/components/schemas/CentralBankReserveMethodology"},"coverage":{"$ref":"#/components/schemas/CentralBankReserveCoverage"},"reserves":{"type":"array","items":{"$ref":"#/components/schemas/CentralBankReserveObservation"}}}},"CentralBankReserveSource":{"type":"object","required":["name","underlying_provider","url","terms_url","available_free_of_charge"],"properties":{"name":{"type":"string","const":"World Bank, World Development Indicators"},"underlying_provider":{"type":"string","const":"International Monetary Fund, International Financial Statistics"},"url":{"type":"string","const":"https://data.worldbank.org/"},"terms_url":{"type":"string","const":"https://data.worldbank.org/summary-terms-of-use"},"available_free_of_charge":{"type":"boolean","const":true}}},"CentralBankReserveMethodology":{"type":"object","required":["gold_reserve_value_usd","annual_gold_value_change_usd","transformation_notice","warning"],"properties":{"gold_reserve_value_usd":{"type":"string","const":"total reserves including gold minus total reserves excluding gold"},"annual_gold_value_change_usd":{"type":"string","const":"current derived gold reserve value minus the prior calendar year"},"transformation_notice":{"type":"string","const":"Bullion API derives gold reserve values, shares, and annual value changes."},"warning":{"type":"string","const":"Annual value changes combine holdings changes, gold-price movement, and revisions and do not measure tonnes bought or sold."}}},"CentralBankReserveCoverage":{"type":"object","required":["countries","start_year","end_year","source_updated_at","fetched_at"],"properties":{"countries":{"type":"integer","minimum":0},"start_year":{"type":["integer","null"]},"end_year":{"type":["integer","null"]},"source_updated_at":{"type":"string","format":"date"},"fetched_at":{"type":"string","format":"date-time"}}},"CentralBankReserveObservation":{"type":"object","required":["country","country_iso3","country_name","as_of_year","total_reserves_usd","reserves_excluding_gold_usd","gold_reserve_value_usd","gold_share_pct","annual_gold_value_change_usd","data_quality"],"properties":{"country":{"type":"string","pattern":"^[A-Z]{2}$"},"country_iso3":{"type":"string","pattern":"^[A-Z]{3}$"},"country_name":{"type":"string"},"as_of_year":{"type":"integer"},"total_reserves_usd":{"type":"number"},"reserves_excluding_gold_usd":{"type":"number"},"gold_reserve_value_usd":{"type":["number","null"]},"gold_share_pct":{"type":["number","null"]},"annual_gold_value_change_usd":{"type":["number","null"]},"data_quality":{"type":["string","null"],"enum":["inconsistent_source_values",null]}}},"CentralBankBadRequestError":{"type":"object","additionalProperties":false,"required":["status","error"],"properties":{"status":{"type":"string","const":"error"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["invalid_country","invalid_year","invalid_range"]},"message":{"type":"string"}}}}},"EmailNotVerifiedError":{"type":"object","additionalProperties":false,"required":["status","error"],"properties":{"status":{"type":"string","const":"error"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","const":"email_not_verified"},"message":{"type":"string"}}}}},"PlanRequiredError":{"type":"object","additionalProperties":false,"required":["status","error"],"properties":{"status":{"type":"string","const":"error"},"error":{"type":"object","additionalProperties":false,"required":["code","message","required_plans","plan"],"properties":{"code":{"type":"string","const":"plan_required"},"message":{"type":"string"},"required_plans":{"type":"array","const":["pro","enterprise"]},"plan":{"type":"string","enum":["free","pro","enterprise"]}}}}},"UsageResponse":{"type":"object","required":["plan","limit","used","remaining","reset_at","subscription","recent","email","email_verified"],"properties":{"plan":{"type":"string","enum":["free","pro","enterprise"]},"limit":{"type":"integer","description":"Monthly request cap for the plan."},"used":{"type":"integer","description":"Requests used this month."},"remaining":{"type":"integer"},"reset_at":{"type":"string","format":"date-time"},"subscription":{"type":"object","required":["status"],"properties":{"status":{"type":["string","null"],"description":"Stripe subscription status, or null on the free plan."}}},"recent":{"type":"array","description":"The 50 most recent API requests, newest first.","items":{"$ref":"#/components/schemas/RecentRequest"}},"email":{"type":"string","format":"email"},"email_verified":{"type":"boolean"}}},"RecentRequest":{"type":"object","required":["endpoint","method","status_code","response_ms","requested_at"],"properties":{"endpoint":{"type":"string","example":"/v1/latest?currency=USD"},"method":{"type":"string","example":"GET"},"status_code":{"type":"integer","example":200},"response_ms":{"type":"integer"},"requested_at":{"type":"string","format":"date-time"}}},"HealthResponse":{"type":"object","required":["status","db_reachable","last_refresh_at","currencies_with_data"],"properties":{"status":{"type":"string","enum":["ok","degraded"]},"db_reachable":{"type":"boolean"},"last_refresh_at":{"type":["string","null"],"format":"date-time","description":"ISO 8601 time of the last successful cache refresh."},"currencies_with_data":{"type":"array","items":{"type":"string"},"description":"Base currencies with at least one cached metal price."}}},"ErrorEnvelope":{"type":"object","additionalProperties":false,"required":["status","error"],"properties":{"status":{"type":"string","const":"error"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["config_error","conflicting_credentials","data_unavailable","email_not_verified","invalid_api_key","invalid_country","invalid_date","invalid_range","invalid_region","invalid_unit","invalid_year","method_not_allowed","missing_api_key","missing_params","plan_required","quota_exceeded","rate_limited","unauthenticated"],"description":"Machine-readable error code."},"message":{"type":"string","description":"Human-readable message."}},"additionalProperties":true}}},"TimeseriesBadRequestError":{"type":"object","additionalProperties":false,"required":["status","error"],"properties":{"status":{"type":"string","const":"error"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["missing_params","invalid_date","invalid_range","invalid_unit"]},"message":{"type":"string"}}}}},"LatestBadRequestError":{"type":"object","additionalProperties":false,"required":["status","error"],"properties":{"status":{"type":"string","const":"error"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","const":"invalid_unit"},"message":{"type":"string"}}}}},"QuotaExceededError":{"type":"object","additionalProperties":false,"required":["status","error"],"properties":{"status":{"type":"string","const":"error"},"error":{"type":"object","additionalProperties":false,"required":["code","message","plan","used","limit","reset_at"],"properties":{"code":{"type":"string","const":"quota_exceeded"},"message":{"type":"string","example":"Your monthly usage limit has been reached. Please upgrade your subscription plan."},"plan":{"type":"string","enum":["free","pro","enterprise"]},"used":{"type":"integer"},"limit":{"type":"integer"},"reset_at":{"type":"string","format":"date-time"}}}}},"RateLimitedError":{"type":"object","additionalProperties":false,"required":["status","error"],"properties":{"status":{"type":"string","const":"error"},"error":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","const":"rate_limited"},"message":{"type":"string","example":"Rate limit exceeded"}}}}}}}}