{
  "openapi": "3.1.0",
  "info": {
    "title": "FirmTape Geo API",
    "version": "1.0.0",
    "summary": "Dated public records of world events, each with its source and time.",
    "description": "Government notices and sanctions, flight restrictions, maritime warnings, internet outages, conflict and disaster records, each against its own normal. The free JSON needs no key and covers the last 30 days. The paid API (API and Team plans, https://firmtape.com/geo/pricing) takes a key, covers a year and returns every field. Guide with examples, webhooks and MCP: https://firmtape.com/geo/docs. Records are context, never a trading signal; credit each record's source and link.",
    "contact": {
      "name": "FirmTape",
      "url": "https://firmtape.com/geo/docs",
      "email": "support@firmtape.com"
    },
    "termsOfService": "https://firmtape.com/terms"
  },
  "externalDocs": {
    "description": "Geo API docs",
    "url": "https://firmtape.com/geo/docs"
  },
  "servers": [
    {
      "url": "https://firmtape.com/geo/api",
      "description": "Free, no key: the last 30 days, as the Geo pages show them"
    },
    {
      "url": "https://geo.firmtape.com",
      "description": "Paid Geo API: API or Team plan key, a year of history"
    }
  ],
  "tags": [
    {
      "name": "Free",
      "description": "No key, the last 30 days"
    },
    {
      "name": "Paid",
      "description": "Authorization: Bearer gk_..., API or Team plan"
    }
  ],
  "paths": {
    "/items": {
      "servers": [
        {
          "url": "https://firmtape.com/geo/api",
          "description": "Free, no key: the last 30 days, as the Geo pages show them"
        }
      ],
      "get": {
        "tags": [
          "Free"
        ],
        "operationId": "freeItems",
        "summary": "Records of one week or a recent range, as the pages show them",
        "parameters": [
          {
            "name": "week",
            "in": "query",
            "required": false,
            "description": "ISO week on the New York calendar, e.g. 2026-W38; replaces range",
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-W\\d{2}$"
            }
          },
          {
            "name": "range",
            "in": "query",
            "required": false,
            "description": "24h, 7d or 30d when no week is given",
            "schema": {
              "type": "string",
              "enum": [
                "24h",
                "7d",
                "30d"
              ],
              "default": "24h"
            }
          },
          {
            "name": "sector",
            "in": "query",
            "required": false,
            "description": "Sector",
            "schema": {
              "type": "string",
              "enum": [
                "gov",
                "air",
                "gps",
                "sea",
                "internet",
                "ground",
                "space",
                "attention"
              ]
            }
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "ISO 3166-1 alpha-2",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "notable",
            "in": "query",
            "required": false,
            "description": "1 keeps only notable records",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Up to 1000",
            "schema": {
              "type": "integer",
              "maximum": 1000,
              "default": 200
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Paging inside a week",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Records, newest first, with week paging links",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Record"
                      }
                    },
                    "next_page": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "prev_week": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "next_week": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/weeks": {
      "servers": [
        {
          "url": "https://firmtape.com/geo/api",
          "description": "Free, no key: the last 30 days, as the Geo pages show them"
        }
      ],
      "get": {
        "tags": [
          "Free"
        ],
        "operationId": "freeWeeks",
        "summary": "Weeks of the last 30 days that hold records, with counts",
        "parameters": [
          {
            "name": "sector",
            "in": "query",
            "required": false,
            "description": "Sector",
            "schema": {
              "type": "string",
              "enum": [
                "gov",
                "air",
                "gps",
                "sea",
                "internet",
                "ground",
                "space",
                "attention"
              ]
            }
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "ISO 3166-1 alpha-2",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Weeks, newest first"
          }
        }
      }
    },
    "/countries": {
      "servers": [
        {
          "url": "https://firmtape.com/geo/api",
          "description": "Free, no key: the last 30 days, as the Geo pages show them"
        }
      ],
      "get": {
        "tags": [
          "Free"
        ],
        "operationId": "freeCountries",
        "summary": "Every country named in the last 30 days, with notable and total counts",
        "responses": {
          "200": {
            "description": "Countries"
          }
        }
      }
    },
    "/health": {
      "servers": [
        {
          "url": "https://firmtape.com/geo/api",
          "description": "Free, no key: the last 30 days, as the Geo pages show them"
        }
      ],
      "get": {
        "tags": [
          "Free"
        ],
        "operationId": "freeSources",
        "summary": "Every feed, how often it is read and when it last answered",
        "responses": {
          "200": {
            "description": "Sources"
          }
        }
      }
    },
    "/v1/items": {
      "servers": [
        {
          "url": "https://geo.firmtape.com",
          "description": "Paid Geo API: API or Team plan key, a year of history"
        }
      ],
      "get": {
        "tags": [
          "Paid"
        ],
        "operationId": "items",
        "summary": "Records, newest first, a year back",
        "security": [
          {
            "key": []
          }
        ],
        "parameters": [
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "ISO 8601 UTC start; default 7 days ago",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "ISO 8601 UTC end; default now",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "sector",
            "in": "query",
            "required": false,
            "description": "Sector",
            "schema": {
              "type": "string",
              "enum": [
                "gov",
                "air",
                "gps",
                "sea",
                "internet",
                "ground",
                "space",
                "attention"
              ]
            }
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "ISO 3166-1 alpha-2",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "feed",
            "in": "query",
            "required": false,
            "description": "One feed id or several, comma separated",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_severity",
            "in": "query",
            "required": false,
            "description": "2 notable and above, 3 critical only",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 3
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Words in the title",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1 to 1000",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 200
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "From next in the previous answer",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Records; next holds the URL of the next page when more match",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "next": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "history_days": {
                      "type": "integer"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Record"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "A parameter is wrong; no call is counted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, unknown key or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "No active API or Team plan, or a key beyond the plan's count",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "This month's calls are used; Retry-After says when the count resets",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sources": {
      "servers": [
        {
          "url": "https://geo.firmtape.com",
          "description": "Paid Geo API: API or Team plan key, a year of history"
        }
      ],
      "get": {
        "tags": [
          "Paid"
        ],
        "operationId": "sources",
        "summary": "Every feed and when it last answered",
        "security": [
          {
            "key": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sources"
          },
          "401": {
            "description": "Bad key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/usage": {
      "servers": [
        {
          "url": "https://geo.firmtape.com",
          "description": "Paid Geo API: API or Team plan key, a year of history"
        }
      ],
      "get": {
        "tags": [
          "Paid"
        ],
        "operationId": "usage",
        "summary": "This month's calls against the plan; not counted",
        "security": [
          {
            "key": []
          }
        ],
        "responses": {
          "200": {
            "description": "Usage",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tier": {
                      "type": "string"
                    },
                    "month": {
                      "type": "string"
                    },
                    "calls": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/export.csv": {
      "servers": [
        {
          "url": "https://geo.firmtape.com",
          "description": "Paid Geo API: API or Team plan key, a year of history"
        }
      ],
      "get": {
        "tags": [
          "Paid"
        ],
        "operationId": "exportCsv",
        "summary": "Every matching record in one CSV: up to 7 days a call on API, 31 on Team",
        "security": [
          {
            "key": []
          }
        ],
        "parameters": [
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "ISO 8601 UTC start",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "ISO 8601 UTC end",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "sector",
            "in": "query",
            "required": false,
            "description": "Sector",
            "schema": {
              "type": "string",
              "enum": [
                "gov",
                "air",
                "gps",
                "sea",
                "internet",
                "ground",
                "space",
                "attention"
              ]
            }
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "ISO 3166-1 alpha-2",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "feed",
            "in": "query",
            "required": false,
            "description": "Feed ids",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_severity",
            "in": "query",
            "required": false,
            "description": "Severity floor",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "CSV",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Window longer than the plan allows",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "key": {
        "type": "http",
        "scheme": "bearer",
        "description": "A Geo API key (gk_...) from https://firmtape.com/account#geo-keys. The same key opens the MCP server at https://geo.firmtape.com/mcp."
      }
    },
    "schemas": {
      "Record": {
        "type": "object",
        "properties": {
          "uid": {
            "type": "string",
            "description": "Stable id of the record"
          },
          "feed": {
            "type": "string",
            "description": "Feed id, see /v1/sources or https://firmtape.com/geo/sources"
          },
          "sector": {
            "type": "string",
            "enum": [
              "gov",
              "air",
              "gps",
              "sea",
              "internet",
              "ground",
              "space",
              "attention"
            ]
          },
          "type": {
            "type": "string",
            "description": "new, update, level_raise, level_lower, cancel, spike, keyword or no_data"
          },
          "category": {
            "type": "string"
          },
          "severity": {
            "type": "integer",
            "description": "0 info, 1 routine, 2 notable, 3 critical"
          },
          "routine": {
            "type": "boolean",
            "description": "True for the records the pages hide by default"
          },
          "countries": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "ISO 3166-1 alpha-2"
          },
          "region": {
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          },
          "published_utc": {
            "type": "string",
            "format": "date-time",
            "description": "When the source published it"
          },
          "event_utc": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the activity happens or starts, when the record says"
          },
          "first_seen_utc": {
            "type": "string",
            "format": "date-time",
            "description": "When FirmTape first read it"
          },
          "backfill": {
            "type": "boolean",
            "description": "Found in the source's own history rather than caught live"
          },
          "source": {
            "type": "string",
            "description": "The publisher to credit"
          },
          "url": {
            "type": "string",
            "description": "The record at its source"
          },
          "attribution": {
            "type": [
              "string",
              "null"
            ],
            "description": "Paid API only: the citation the source asks for"
          },
          "value": {
            "type": [
              "number",
              "null"
            ],
            "description": "Spikes: what was measured"
          },
          "baseline": {
            "type": [
              "number",
              "null"
            ],
            "description": "Spikes: its own normal"
          },
          "score": {
            "type": [
              "number",
              "null"
            ],
            "description": "Spikes: value against the normal"
          },
          "lat": {
            "type": [
              "number",
              "null"
            ],
            "description": "Paid API only"
          },
          "lon": {
            "type": [
              "number",
              "null"
            ],
            "description": "Paid API only"
          },
          "facts": {
            "type": "object",
            "description": "Paid API only: source-specific details"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          }
        }
      }
    }
  },
  "x-mcp": {
    "url": "https://geo.firmtape.com/mcp",
    "transport": "streamable-http",
    "tools": [
      "geo_records",
      "geo_sources"
    ],
    "auth": "Authorization: Bearer gk_..."
  },
  "x-webhooks-signature": "X-FirmTape-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, t + \".\" + raw body)>"
}