{
  "openapi": "3.1.0",
  "info": {
    "title": "FX Bank Forecast API",
    "version": "1.0.0",
    "summary": "Read-only JSON access to investment-bank FX/gold/oil consensus, live rates, CFTC positioning, the macro calendar, and forecast-intelligence endpoints.",
    "description": "All endpoints are read-only GET. Two independent access concepts apply:\n\n1. **Rate limits** — anonymous callers get 60 req/min per IP; signed-in paid subscribers get 600 req/min; a valid `Authorization: Bearer fbf_sk_…` API key gets a 6,000 req/min burst window metered against the key's monthly quota (10k / 100k / 10M by plan — see /pricing#api).\n\n2. **Content tier** — premium endpoints additionally require the calling ACCOUNT to hold a Retail or Pro subscription. A Bearer API key satisfies this with the tier of its owning account; every paid API plan is provisioned at Pro content tier, so any paid API key can call every endpoint in this spec. Free self-serve keys raise rate limits only.\n\nKeys are issued from /account/api (shown once at creation). Every response carries X-RateLimit-* headers so clients can self-throttle.",
    "termsOfService": "https://fxbankforecast.com/terms",
    "contact": {
      "name": "FX Bank Forecast",
      "email": "coverage@fxbankforecast.com",
      "url": "https://fxbankforecast.com/api-docs"
    }
  },
  "servers": [
    {
      "url": "https://fxbankforecast.com"
    }
  ],
  "security": [
    {},
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Meta",
      "description": "Auth and quota introspection."
    },
    {
      "name": "Market Data",
      "description": "Live spot reference prices. No authentication required."
    },
    {
      "name": "Consensus & Forecasts",
      "description": "Cross-firm bank consensus and per-firm research."
    },
    {
      "name": "Positioning & Calendar",
      "description": "CFTC positioning and the macro economic calendar."
    },
    {
      "name": "Intelligence",
      "description": "Scored surprises, distributions, revision leadership, hit rates, and outliers. Pro tier."
    }
  ],
  "paths": {
    "/api/me": {
      "get": {
        "tags": [
          "Meta"
        ],
        "summary": "Current rate-limit class and quota",
        "description": "Session-cookie introspection probe. NOTE: this endpoint is outside the API-key surface — a Bearer key is ignored here (it never counts against your quota).",
        "operationId": "getMe",
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "authenticated": {
                      "type": "boolean"
                    },
                    "email": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "tier": {
                      "type": "string",
                      "enum": [
                        "anon",
                        "authed",
                        "apiKey"
                      ]
                    },
                    "coverageTier": {
                      "type": "string",
                      "enum": [
                        "free",
                        "retail",
                        "pro",
                        "team"
                      ]
                    },
                    "subscriberStatus": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "stripeActive": {
                      "type": "boolean"
                    },
                    "renewsAt": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "trialing": {
                      "type": "boolean"
                    },
                    "trialEndsAt": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "daysUntilTrialEnd": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "rateLimit": {
                      "type": "object",
                      "properties": {
                        "perMinute": {
                          "type": "integer"
                        },
                        "window": {
                          "type": "string",
                          "const": "60s"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (burst window) — or, for API-key callers, monthly quota exhausted (`quota_exceeded` with `resetAt`).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until the next request is permitted.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "burst": {
                    "value": {
                      "error": "rate_limit_exceeded",
                      "message": "Rate limit exceeded. Please throttle requests.",
                      "retryAfter": 12
                    }
                  },
                  "quota": {
                    "value": {
                      "error": "quota_exceeded",
                      "message": "Monthly request quota exhausted.",
                      "resetAt": "2026-08-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/rates": {
      "get": {
        "tags": [
          "Market Data"
        ],
        "summary": "Live FX spot rates (USD base, 28 currencies)",
        "description": "CDN-cached ~30s (`Cache-Control: public, s-maxage=30, stale-while-revalidate=60`). `source` names the upstream provider chain; a `stale-cache` source may add a `warning` field.",
        "operationId": "getRates",
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "rates": {
                      "type": "object",
                      "description": "ISO-4217 code → units per USD (null when a currency is temporarily unavailable).",
                      "additionalProperties": {
                        "type": [
                          "number",
                          "null"
                        ]
                      }
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "source": {
                      "type": "string"
                    },
                    "base": {
                      "type": "string",
                      "const": "USD"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (burst window) — or, for API-key callers, monthly quota exhausted (`quota_exceeded` with `resetAt`).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until the next request is permitted.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "burst": {
                    "value": {
                      "error": "rate_limit_exceeded",
                      "message": "Rate limit exceeded. Please throttle requests.",
                      "retryAfter": 12
                    }
                  },
                  "quota": {
                    "value": {
                      "error": "quota_exceeded",
                      "message": "Monthly request quota exhausted.",
                      "resetAt": "2026-08-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "All rate providers and caches unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/gold-price": {
      "get": {
        "tags": [
          "Market Data"
        ],
        "summary": "Live gold spot (USD/oz) with intraday change and history",
        "operationId": "getGoldPrice",
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommodityPrice"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (burst window) — or, for API-key callers, monthly quota exhausted (`quota_exceeded` with `resetAt`).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until the next request is permitted.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "burst": {
                    "value": {
                      "error": "rate_limit_exceeded",
                      "message": "Rate limit exceeded. Please throttle requests.",
                      "retryAfter": 12
                    }
                  },
                  "quota": {
                    "value": {
                      "error": "quota_exceeded",
                      "message": "Monthly request quota exhausted.",
                      "resetAt": "2026-08-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "All providers and caches unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/oil-price": {
      "get": {
        "tags": [
          "Market Data"
        ],
        "summary": "Live WTI crude spot (USD/bbl) with intraday change and history",
        "operationId": "getOilPrice",
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommodityPrice"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (burst window) — or, for API-key callers, monthly quota exhausted (`quota_exceeded` with `resetAt`).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until the next request is permitted.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "burst": {
                    "value": {
                      "error": "rate_limit_exceeded",
                      "message": "Rate limit exceeded. Please throttle requests.",
                      "retryAfter": 12
                    }
                  },
                  "quota": {
                    "value": {
                      "error": "quota_exceeded",
                      "message": "Monthly request quota exhausted.",
                      "resetAt": "2026-08-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "All providers and caches unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/consensus": {
      "get": {
        "tags": [
          "Consensus & Forecasts"
        ],
        "summary": "Cross-firm consensus forecasts for major pairs",
        "operationId": "getConsensus",
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "consensus": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "currency": {
                            "type": "string"
                          },
                          "isIndex": {
                            "type": "boolean"
                          },
                          "firmCount": {
                            "type": "integer"
                          },
                          "currentSpot": {
                            "type": "number"
                          },
                          "mar26": {
                            "type": "number"
                          },
                          "jun26": {
                            "type": "number"
                          },
                          "sep26": {
                            "type": "number"
                          },
                          "dec26": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (burst window) — or, for API-key callers, monthly quota exhausted (`quota_exceeded` with `resetAt`).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until the next request is permitted.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "burst": {
                    "value": {
                      "error": "rate_limit_exceeded",
                      "message": "Rate limit exceeded. Please throttle requests.",
                      "retryAfter": 12
                    }
                  },
                  "quota": {
                    "value": {
                      "error": "quota_exceeded",
                      "message": "Monthly request quota exhausted.",
                      "resetAt": "2026-08-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/positioning": {
      "get": {
        "tags": [
          "Positioning & Calendar"
        ],
        "summary": "CFTC COT institutional positioning (26-week series)",
        "description": "CDN-cached 1h (`public, s-maxage=3600, stale-while-revalidate=7200`).",
        "operationId": "getPositioning",
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "positioning": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "currency": {
                            "type": "string"
                          },
                          "marketName": {
                            "type": "string"
                          },
                          "latest": {
                            "type": "object",
                            "properties": {
                              "reportDate": {
                                "type": "string",
                                "format": "date"
                              },
                              "noncommNet": {
                                "type": "number"
                              },
                              "noncommNetChg": {
                                "type": [
                                  "number",
                                  "null"
                                ]
                              },
                              "noncommLong": {
                                "type": "number"
                              },
                              "noncommShort": {
                                "type": "number"
                              },
                              "commNet": {
                                "type": "number"
                              },
                              "openInterest": {
                                "type": "number"
                              }
                            }
                          },
                          "series": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "reportDate": {
                                  "type": "string",
                                  "format": "date"
                                },
                                "noncommNet": {
                                  "type": "number"
                                },
                                "openInterest": {
                                  "type": "number"
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "lastUpdated": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "count": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (burst window) — or, for API-key callers, monthly quota exhausted (`quota_exceeded` with `resetAt`).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until the next request is permitted.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "burst": {
                    "value": {
                      "error": "rate_limit_exceeded",
                      "message": "Rate limit exceeded. Please throttle requests.",
                      "retryAfter": 12
                    }
                  },
                  "quota": {
                    "value": {
                      "error": "quota_exceeded",
                      "message": "Monthly request quota exhausted.",
                      "resetAt": "2026-08-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/economic-events": {
      "get": {
        "tags": [
          "Positioning & Calendar"
        ],
        "summary": "Macro calendar events",
        "description": "Anonymous/free callers are clamped to a 7-day window each way; Retail+ accounts get up to 90 days. The clamp is silent — inspect the `window` block in the response.",
        "operationId": "getEconomicEvents",
        "parameters": [
          {
            "name": "days_back",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 14
            },
            "description": "Days of history. Clamped to the tier max (7 free / 90 Retail+)."
          },
          {
            "name": "days_ahead",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 30
            },
            "description": "Days forward. Clamped to the tier max (7 free / 90 Retail+)."
          },
          {
            "name": "impact",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated filter: high,medium,low."
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "events": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "source": {
                            "type": "string"
                          },
                          "externalId": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "eventName": {
                            "type": "string"
                          },
                          "country": {
                            "type": "string"
                          },
                          "currency": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "date": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "impact": {
                            "type": "string"
                          },
                          "actual": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "estimate": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "previous": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "changePct": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "unit": {
                            "type": [
                              "string",
                              "null"
                            ]
                          }
                        }
                      }
                    },
                    "lastUpdated": {
                      "type": "string"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "window": {
                      "type": "object",
                      "properties": {
                        "daysBack": {
                          "type": "integer"
                        },
                        "daysAhead": {
                          "type": "integer"
                        },
                        "maxDays": {
                          "type": "integer"
                        }
                      }
                    },
                    "tier": {
                      "type": "string",
                      "enum": [
                        "free",
                        "retail",
                        "pro",
                        "team"
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (burst window) — or, for API-key callers, monthly quota exhausted (`quota_exceeded` with `resetAt`).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until the next request is permitted.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "burst": {
                    "value": {
                      "error": "rate_limit_exceeded",
                      "message": "Rate limit exceeded. Please throttle requests.",
                      "retryAfter": 12
                    }
                  },
                  "quota": {
                    "value": {
                      "error": "quota_exceeded",
                      "message": "Monthly request quota exhausted.",
                      "resetAt": "2026-08-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/firms": {
      "get": {
        "tags": [
          "Consensus & Forecasts"
        ],
        "summary": "Covered sell-side institutions (Retail tier)",
        "operationId": "getFirms",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "firms": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/FirmMeta"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Malformed or revoked API key (`invalid_api_key` / `api_key_revoked`). Requests WITHOUT an Authorization header are never rejected with 401 — they are treated as anonymous.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The firm catalogue requires an account at Retail tier or above: either a signed-in session or a Bearer API key whose owning account is entitled. Every paid API plan is provisioned at Pro content tier, so any paid API key passes this gate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "retail_tier_required"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (burst window) — or, for API-key callers, monthly quota exhausted (`quota_exceeded` with `resetAt`).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until the next request is permitted.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "burst": {
                    "value": {
                      "error": "rate_limit_exceeded",
                      "message": "Rate limit exceeded. Please throttle requests.",
                      "retryAfter": 12
                    }
                  },
                  "quota": {
                    "value": {
                      "error": "quota_exceeded",
                      "message": "Monthly request quota exhausted.",
                      "resetAt": "2026-08-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/firms/{firm}": {
      "get": {
        "tags": [
          "Consensus & Forecasts"
        ],
        "summary": "Full research report for one institution (Retail tier)",
        "operationId": "getFirmReport",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "firm",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Firm id, e.g. `goldman`, `jpmorgan` — see /api/firms."
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "report": {
                      "type": "object",
                      "description": "meta + per-section research blocks. Sections a firm's latest report did not include are omitted or empty.",
                      "properties": {
                        "meta": {
                          "$ref": "#/components/schemas/FirmMeta"
                        },
                        "forecasts": {
                          "type": "object",
                          "properties": {
                            "vsUSD": {
                              "type": "array",
                              "items": {
                                "$ref": "#/components/schemas/FXForecast"
                              }
                            },
                            "indices": {
                              "type": "array",
                              "items": {
                                "$ref": "#/components/schemas/FXForecast"
                              }
                            }
                          }
                        }
                      },
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Malformed or revoked API key (`invalid_api_key` / `api_key_revoked`). Requests WITHOUT an Authorization header are never rejected with 401 — they are treated as anonymous.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Per-firm research requires an account at Retail tier or above: either a signed-in session or a Bearer API key whose owning account is entitled. Every paid API plan is provisioned at Pro content tier, so any paid API key passes this gate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "retail_tier_required"
                }
              }
            }
          },
          "404": {
            "description": "Unknown firm id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (burst window) — or, for API-key callers, monthly quota exhausted (`quota_exceeded` with `resetAt`).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until the next request is permitted.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "burst": {
                    "value": {
                      "error": "rate_limit_exceeded",
                      "message": "Rate limit exceeded. Please throttle requests.",
                      "retryAfter": 12
                    }
                  },
                  "quota": {
                    "value": {
                      "error": "quota_exceeded",
                      "message": "Monthly request quota exhausted.",
                      "resetAt": "2026-08-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/compare": {
      "get": {
        "tags": [
          "Consensus & Forecasts"
        ],
        "summary": "Cross-firm forecast comparison (Retail tier)",
        "operationId": "getCompare",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "currency",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Single currency code (e.g. EUR). Omit for all firms' full forecast sets."
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "With ?currency: `{ comparisons: [{ firmId, firmName, firmShortName, firmColor, bias?, forecast }] }`. Without: `{ allForecasts: [{ firmId, firmName, firmColor, forecasts: { vsUSD, indices } }] }`.",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Malformed or revoked API key (`invalid_api_key` / `api_key_revoked`). Requests WITHOUT an Authorization header are never rejected with 401 — they are treated as anonymous.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forecast comparison requires an account at Retail tier or above: either a signed-in session or a Bearer API key whose owning account is entitled. Every paid API plan is provisioned at Pro content tier, so any paid API key passes this gate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "retail_tier_required"
                }
              }
            }
          },
          "404": {
            "description": "No forecasts for the requested currency.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (burst window) — or, for API-key callers, monthly quota exhausted (`quota_exceeded` with `resetAt`).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until the next request is permitted.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "burst": {
                    "value": {
                      "error": "rate_limit_exceeded",
                      "message": "Rate limit exceeded. Please throttle requests.",
                      "retryAfter": 12
                    }
                  },
                  "quota": {
                    "value": {
                      "error": "quota_exceeded",
                      "message": "Monthly request quota exhausted.",
                      "resetAt": "2026-08-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/track-record": {
      "get": {
        "tags": [
          "Consensus & Forecasts"
        ],
        "summary": "Historical forecast accuracy by firm and year (Retail tier)",
        "operationId": "getTrackRecord",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "source": {
                      "type": "string",
                      "const": "database"
                    },
                    "years": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "year": {
                            "type": "integer"
                          },
                          "label": {
                            "type": "string"
                          },
                          "actuals": {
                            "type": "object",
                            "additionalProperties": {
                              "type": "object",
                              "properties": {
                                "spotNovPrior": {
                                  "type": "number"
                                },
                                "q1": {
                                  "type": "number"
                                },
                                "q2": {
                                  "type": "number"
                                },
                                "q3": {
                                  "type": "number"
                                },
                                "eoy": {
                                  "type": "number"
                                }
                              }
                            }
                          },
                          "firms": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "firmId": {
                                  "type": "string"
                                },
                                "firmName": {
                                  "type": "string"
                                },
                                "firmShortName": {
                                  "type": "string"
                                },
                                "firmColor": {
                                  "type": "string"
                                },
                                "reportDate": {
                                  "type": "string"
                                },
                                "forecasts": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "currency": {
                                        "type": "string"
                                      },
                                      "region": {
                                        "type": "string"
                                      },
                                      "spotAtForecast": {
                                        "type": "number"
                                      },
                                      "targetEOY": {
                                        "type": "number"
                                      },
                                      "q1": {
                                        "type": "number"
                                      },
                                      "q2": {
                                        "type": "number"
                                      },
                                      "q3": {
                                        "type": "number"
                                      }
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Malformed or revoked API key (`invalid_api_key` / `api_key_revoked`). Requests WITHOUT an Authorization header are never rejected with 401 — they are treated as anonymous.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The track record requires an account at Retail tier or above: either a signed-in session or a Bearer API key whose owning account is entitled. Every paid API plan is provisioned at Pro content tier, so any paid API key passes this gate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "retail_tier_required"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (burst window) — or, for API-key callers, monthly quota exhausted (`quota_exceeded` with `resetAt`).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until the next request is permitted.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "burst": {
                    "value": {
                      "error": "rate_limit_exceeded",
                      "message": "Rate limit exceeded. Please throttle requests.",
                      "retryAfter": 12
                    }
                  },
                  "quota": {
                    "value": {
                      "error": "quota_exceeded",
                      "message": "Monthly request quota exhausted.",
                      "resetAt": "2026-08-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Database fetch failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/surprises": {
      "get": {
        "tags": [
          "Intelligence"
        ],
        "summary": "Scored economic-print surprises (Pro tier)",
        "description": "Actual vs estimate per print, with the count of bank forecast revisions that reacted within 5 days.",
        "operationId": "getSurprises",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "currency",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[A-Z]{3}$"
            }
          },
          {
            "name": "impact",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "high",
                "medium",
                "low"
              ]
            }
          },
          {
            "name": "fromDate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "toDate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "filter": {
                      "type": "object",
                      "additionalProperties": true
                    },
                    "rows": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "economicEventId": {
                            "type": "string"
                          },
                          "eventName": {
                            "type": "string"
                          },
                          "country": {
                            "type": "string"
                          },
                          "currency": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "impact": {
                            "type": "string"
                          },
                          "date": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "actualNumeric": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "estimateNumeric": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "surpriseRaw": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "surprisePct": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "reactionCount": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_currency / unknown_impact.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Malformed or revoked API key (`invalid_api_key` / `api_key_revoked`). Requests WITHOUT an Authorization header are never rejected with 401 — they are treated as anonymous.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The Surprises API requires an account at Pro tier or above: either a signed-in session or a Bearer API key whose owning account is entitled. Every paid API plan is provisioned at Pro content tier, so any paid API key passes this gate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "pro_tier_required",
                  "message": "Requires a Pro subscription. Subscribe at /pricing.",
                  "currentTier": "free"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (burst window) — or, for API-key callers, monthly quota exhausted (`quota_exceeded` with `resetAt`).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until the next request is permitted.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "burst": {
                    "value": {
                      "error": "rate_limit_exceeded",
                      "message": "Rate limit exceeded. Please throttle requests.",
                      "retryAfter": 12
                    }
                  },
                  "quota": {
                    "value": {
                      "error": "quota_exceeded",
                      "message": "Monthly request quota exhausted.",
                      "resetAt": "2026-08-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/distribution": {
      "get": {
        "tags": [
          "Intelligence"
        ],
        "summary": "Statistical forecast distribution for a pair (Pro tier)",
        "description": "Latest 51-point probability density blending bank consensus dispersion with realized volatility.",
        "operationId": "getDistribution",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "pair",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Z0-9]{3,8}$"
            },
            "description": "e.g. EURUSD, WTI, XAUUSD."
          },
          {
            "name": "tenor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "enum": [
                30,
                90,
                365
              ],
              "default": 30
            },
            "description": "Horizon in days."
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "pair": {
                      "type": "string"
                    },
                    "asOfDate": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "tenorDays": {
                      "type": "integer"
                    },
                    "methodologyVersion": {
                      "type": "string"
                    },
                    "baseSpot": {
                      "type": "number"
                    },
                    "forwardEstimate": {
                      "type": "number"
                    },
                    "atmVolAnnualized": {
                      "type": "number"
                    },
                    "skewness": {
                      "type": "number"
                    },
                    "kurtosis": {
                      "type": "number"
                    },
                    "distributionPoints": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "strike": {
                            "type": "number"
                          },
                          "pdf": {
                            "type": "number"
                          },
                          "cdf": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "missing_pair / invalid_pair / invalid_tenor.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Malformed or revoked API key (`invalid_api_key` / `api_key_revoked`). Requests WITHOUT an Authorization header are never rejected with 401 — they are treated as anonymous.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The Distribution API requires an account at Pro tier or above: either a signed-in session or a Bearer API key whose owning account is entitled. Every paid API plan is provisioned at Pro content tier, so any paid API key passes this gate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "pro_tier_required",
                  "message": "Requires a Pro subscription. Subscribe at /pricing.",
                  "currentTier": "free"
                }
              }
            }
          },
          "404": {
            "description": "No distribution computed for this pair/tenor.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (burst window) — or, for API-key callers, monthly quota exhausted (`quota_exceeded` with `resetAt`).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until the next request is permitted.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "burst": {
                    "value": {
                      "error": "rate_limit_exceeded",
                      "message": "Rate limit exceeded. Please throttle requests.",
                      "retryAfter": 12
                    }
                  },
                  "quota": {
                    "value": {
                      "error": "quota_exceeded",
                      "message": "Monthly request quota exhausted.",
                      "resetAt": "2026-08-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/leaders": {
      "get": {
        "tags": [
          "Intelligence"
        ],
        "summary": "Revision-leadership rankings (Pro tier)",
        "description": "Which firms move consensus first, on a rolling 18-month window. With BOTH pair and horizon: a flat ranked list. Otherwise: top-5 groups per (pair × horizon).",
        "operationId": "getLeaders",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "pair",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[A-Z0-9]{3,8}$"
            },
            "description": "Single-currency code, e.g. EUR, JPY, GBP."
          },
          {
            "name": "horizon",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "short",
                "mid",
                "long"
              ]
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "windowKind": {
                      "type": "string",
                      "const": "rolling-18mo"
                    },
                    "filter": {
                      "type": "object",
                      "additionalProperties": true
                    },
                    "rows": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LeaderRow"
                      },
                      "description": "Present when both pair and horizon are given."
                    },
                    "groups": {
                      "type": "array",
                      "description": "Present on the overview (pair or horizon omitted).",
                      "items": {
                        "type": "object",
                        "properties": {
                          "pair": {
                            "type": "string"
                          },
                          "horizon": {
                            "type": "string"
                          },
                          "top": {
                            "type": "array",
                            "items": {
                              "$ref": "#/components/schemas/LeaderRow"
                            }
                          }
                        }
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "unknown_horizon / invalid_pair.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Malformed or revoked API key (`invalid_api_key` / `api_key_revoked`). Requests WITHOUT an Authorization header are never rejected with 401 — they are treated as anonymous.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The Leaders API requires an account at Pro tier or above: either a signed-in session or a Bearer API key whose owning account is entitled. Every paid API plan is provisioned at Pro content tier, so any paid API key passes this gate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "pro_tier_required",
                  "message": "Requires a Pro subscription. Subscribe at /pricing.",
                  "currentTier": "free"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (burst window) — or, for API-key callers, monthly quota exhausted (`quota_exceeded` with `resetAt`).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until the next request is permitted.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "burst": {
                    "value": {
                      "error": "rate_limit_exceeded",
                      "message": "Rate limit exceeded. Please throttle requests.",
                      "retryAfter": 12
                    }
                  },
                  "quota": {
                    "value": {
                      "error": "quota_exceeded",
                      "message": "Monthly request quota exhausted.",
                      "resetAt": "2026-08-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/leaderboard": {
      "get": {
        "tags": [
          "Intelligence"
        ],
        "summary": "Rolling-1y hit-rate leaderboard cards (Pro tier)",
        "operationId": "getLeaderboard",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "asset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "fx",
                "oil",
                "gold"
              ],
              "default": "fx"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "asset": {
                      "type": "string"
                    },
                    "pairs": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "rollups": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "pair": {
                            "type": "string"
                          },
                          "horizonBucket": {
                            "type": "string"
                          },
                          "windowKind": {
                            "type": "string",
                            "const": "rolling-1y"
                          },
                          "windowEnd": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "computedAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "rows": {
                            "type": "array",
                            "maxItems": 20,
                            "items": {
                              "type": "object",
                              "properties": {
                                "rank": {
                                  "type": [
                                    "integer",
                                    "null"
                                  ]
                                },
                                "firmId": {
                                  "type": "string"
                                },
                                "firmName": {
                                  "type": "string"
                                },
                                "firmShortName": {
                                  "type": "string"
                                },
                                "firmColor": {
                                  "type": [
                                    "string",
                                    "null"
                                  ]
                                },
                                "compositeScore": {
                                  "type": "number"
                                },
                                "meanAbsErrorPct": {
                                  "type": "number"
                                },
                                "meanSignedError": {
                                  "type": "number"
                                },
                                "directionalAccuracy": {
                                  "type": "number"
                                },
                                "sampleSize": {
                                  "type": "integer"
                                },
                                "status": {
                                  "type": "string",
                                  "enum": [
                                    "ranked",
                                    "unranked"
                                  ]
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "unknown_asset.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Malformed or revoked API key (`invalid_api_key` / `api_key_revoked`). Requests WITHOUT an Authorization header are never rejected with 401 — they are treated as anonymous.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The Hit-Rate Leaderboard API requires an account at Pro tier or above: either a signed-in session or a Bearer API key whose owning account is entitled. Every paid API plan is provisioned at Pro content tier, so any paid API key passes this gate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "pro_tier_required",
                  "message": "Requires a Pro subscription. Subscribe at /pricing.",
                  "currentTier": "free"
                }
              }
            }
          },
          "404": {
            "description": "No rollups computed yet for this asset.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (burst window) — or, for API-key callers, monthly quota exhausted (`quota_exceeded` with `resetAt`).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until the next request is permitted.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "burst": {
                    "value": {
                      "error": "rate_limit_exceeded",
                      "message": "Rate limit exceeded. Please throttle requests.",
                      "retryAfter": 12
                    }
                  },
                  "quota": {
                    "value": {
                      "error": "quota_exceeded",
                      "message": "Monthly request quota exhausted.",
                      "resetAt": "2026-08-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/outliers": {
      "get": {
        "tags": [
          "Intelligence"
        ],
        "summary": "Active out-of-consensus forecasts (Pro tier)",
        "description": "Currently-unresolved forecasts sitting far from the cross-firm consensus, with sigma deviation.",
        "operationId": "getOutliers",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "pair",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[A-Z0-9]{3,8}$"
            }
          },
          {
            "name": "horizon",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "short",
                "mid",
                "long"
              ]
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "filter": {
                      "type": "object",
                      "additionalProperties": true
                    },
                    "rows": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "firmId": {
                            "type": "string"
                          },
                          "firmName": {
                            "type": "string"
                          },
                          "firmShortName": {
                            "type": "string"
                          },
                          "firmColor": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "pair": {
                            "type": "string"
                          },
                          "horizonBucket": {
                            "type": "string"
                          },
                          "targetYear": {
                            "type": "integer"
                          },
                          "targetQuarter": {
                            "type": "integer"
                          },
                          "forecastValue": {
                            "type": "number"
                          },
                          "consensusMean": {
                            "type": "number"
                          },
                          "consensusStdDev": {
                            "type": "number"
                          },
                          "deviationSigma": {
                            "type": "number"
                          },
                          "sampleSize": {
                            "type": "integer"
                          },
                          "detectedAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "resolvedAt": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "unknown_horizon / invalid_pair.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Malformed or revoked API key (`invalid_api_key` / `api_key_revoked`). Requests WITHOUT an Authorization header are never rejected with 401 — they are treated as anonymous.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The Outliers API requires an account at Pro tier or above: either a signed-in session or a Bearer API key whose owning account is entitled. Every paid API plan is provisioned at Pro content tier, so any paid API key passes this gate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "pro_tier_required",
                  "message": "Requires a Pro subscription. Subscribe at /pricing.",
                  "currentTier": "free"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (burst window) — or, for API-key callers, monthly quota exhausted (`quota_exceeded` with `resetAt`).",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Requests permitted in the current window (burst window for anonymous/session callers; monthly quota for API-key callers).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining before the limit is reached.",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Window reset time (UTC Unix seconds).",
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Tier": {
                "description": "Present on API-key requests only — the key tier (starter | pro | enterprise).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds until the next request is permitted.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "burst": {
                    "value": {
                      "error": "rate_limit_exceeded",
                      "message": "Rate limit exceeded. Please throttle requests.",
                      "retryAfter": 12
                    }
                  },
                  "quota": {
                    "value": {
                      "error": "quota_exceeded",
                      "message": "Monthly request quota exhausted.",
                      "resetAt": "2026-08-01T00:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Customer API key (`fbf_sk_…`), issued from /account/api. Raises the burst limit to 6,000 req/min, meters usage against the plan's monthly quota, and carries the owning account's content tier for the Retail/Pro-gated endpoints."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ],
        "additionalProperties": true
      },
      "Pagination": {
        "type": "object",
        "description": "Standard pagination block on /api/v1/* list endpoints. Defaults: page=1, pageSize=100 (max 500). Out-of-range values clamp silently.",
        "properties": {
          "page": {
            "type": "integer"
          },
          "pageSize": {
            "type": "integer"
          },
          "totalRows": {
            "type": "integer"
          },
          "totalPages": {
            "type": "integer"
          },
          "nextUrl": {
            "type": [
              "string",
              "null"
            ],
            "description": "Path-relative URL of the next page, or null on the last page."
          }
        }
      },
      "CommodityPrice": {
        "type": "object",
        "properties": {
          "price": {
            "type": "number"
          },
          "change": {
            "type": [
              "number",
              "null"
            ]
          },
          "changePct": {
            "type": [
              "number",
              "null"
            ]
          },
          "high": {
            "type": "number"
          },
          "low": {
            "type": "number"
          },
          "prevClose": {
            "type": "number"
          },
          "history": {
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "source": {
            "type": "string"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "FirmMeta": {
        "type": "object",
        "properties": {
          "firmId": {
            "type": "string"
          },
          "firmName": {
            "type": "string"
          },
          "firmShortName": {
            "type": "string"
          },
          "firmColor": {
            "type": "string"
          },
          "firmColorLight": {
            "type": "string"
          },
          "reportTitle": {
            "type": "string"
          },
          "reportSubtitle": {
            "type": "string"
          },
          "reportDate": {
            "type": "string"
          },
          "leadAnalysts": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "usdBias": {
            "type": "string",
            "enum": [
              "bullish",
              "bearish",
              "neutral"
            ]
          }
        },
        "additionalProperties": true
      },
      "FXForecast": {
        "type": "object",
        "properties": {
          "currency": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "currentSpot": {
            "type": "number"
          },
          "mar26": {
            "type": "number"
          },
          "jun26": {
            "type": "number"
          },
          "sep26": {
            "type": "number"
          },
          "dec26": {
            "type": "number"
          },
          "firmGainVsSpot": {
            "type": "number"
          },
          "firmGainVsForwards": {
            "type": "number"
          },
          "firmGainVsConsensus": {
            "type": "number"
          },
          "chg1m": {
            "type": "number"
          },
          "chg3m": {
            "type": "number"
          },
          "chgYtd": {
            "type": "number"
          },
          "chg12m": {
            "type": "number"
          }
        },
        "additionalProperties": true
      },
      "LeaderRow": {
        "type": "object",
        "properties": {
          "firmId": {
            "type": "string"
          },
          "firmName": {
            "type": "string"
          },
          "firmShortName": {
            "type": "string"
          },
          "firmColor": {
            "type": [
              "string",
              "null"
            ]
          },
          "pair": {
            "type": "string"
          },
          "horizonBucket": {
            "type": "string"
          },
          "windowKind": {
            "type": "string"
          },
          "windowStart": {
            "type": "string",
            "format": "date-time"
          },
          "windowEnd": {
            "type": "string",
            "format": "date-time"
          },
          "revisionCount": {
            "type": "integer"
          },
          "leadCount": {
            "type": "integer"
          },
          "followCount": {
            "type": "integer"
          },
          "contraCount": {
            "type": "integer"
          },
          "leadScore": {
            "type": [
              "number",
              "null"
            ]
          },
          "rank": {
            "type": [
              "integer",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "ranked",
              "unranked"
            ]
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    }
  }
}