{
  "openapi": "3.1.0",
  "info": {
    "title": "gtm:free API",
    "version": "0.7.0",
    "summary": "Free GTM tools through a shared, asynchronous job API.",
    "description": "Public REST API contract implemented by the gateway. Google Maps geographic scraping is the first tool. Use a verified-email gtm:free API key as a Bearer credential. Jobs belong to the enrolled user, with one active job per user per tool across REST, MCP, SDK and website calls. Website account/key-management routes and MCP OAuth are separate interfaces. Network policy permits EU/EEA, UK, Switzerland, Andorra, Monaco, San Marino, Isle of Man, Jersey, Guernsey, Gibraltar, US, Canada, Australia and New Zealand. Country and Spamhaus restrictions apply throughout; datacenter screening applies only to enrollment. Edge failures may be non-JSON. No cancellation or retention SLA is promised.",
    "contact": {
      "email": "hello@gtmfree.com"
    },
    "termsOfService": "https://gtmfree.com/terms/"
  },
  "servers": [
    {
      "url": "https://gtmfree.com/api/v1",
      "description": "Production API"
    }
  ],
  "tags": [
    {
      "name": "Account",
      "description": "Check the owner and limits of your API key."
    },
    {
      "name": "Tools",
      "description": "Discovery."
    },
    {
      "name": "Google Maps",
      "description": "Geographic scraping."
    },
    {
      "name": "Jobs",
      "description": "Owned job status, events and results."
    },
    {
      "name": "Regions",
      "description": "Discover countries, supported subdivision levels and exact administrative areas from geoBoundaries gbOpen. Preserve attribution."
    }
  ],
  "security": [
    {
      "ApiKeyBearer": []
    }
  ],
  "paths": {
    "/me": {
      "get": {
        "operationId": "getCurrentUser",
        "summary": "Check your API key and account limits",
        "description": "Authenticate the Bearer key and check the authoritative email verification state. Returns only its enrolled, verified, non-banned owner. Website cookies and authentication-provider server secrets are not REST credentials.",
        "tags": [
          "Account"
        ],
        "x-mcp-expose": false,
        "responses": {
          "200": {
            "description": "Authenticated account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CurrentUser"
                },
                "example": {
                  "user_id": "da9c0ac2-bab9-4cd9-a0b7-8ef6e9cdf579",
                  "email": "you@example.com",
                  "email_verified": true,
                  "limits": {
                    "maximum_active_jobs_per_tool": 1
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/NoStore"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "GTMFree-Limits": {
                "$ref": "#/components/headers/Limits"
              },
              "GTMFree-Limits-Status": {
                "$ref": "#/components/headers/LimitsStatus"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/RequestTimeout"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          }
        }
      }
    },
    "/tools": {
      "get": {
        "operationId": "listTools",
        "summary": "List supported tools",
        "description": "This version covers Google Maps only. Other platform tools are outside this iteration. Public discovery still follows country/Spamhaus policy. Available does not guarantee temporary worker capacity. An unconfigured, missing or insecure local worker socket is unavailable. Socket presence is only a local preflight; it does not prove worker health.",
        "tags": [
          "Tools"
        ],
        "security": [],
        "x-mcp-expose": true,
        "responses": {
          "200": {
            "description": "Tool catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolList"
                },
                "example": {
                  "items": [
                    {
                      "id": "google-maps-scraper",
                      "name": "Google Maps Scraper",
                      "availability": "available",
                      "description": "Geographic discovery of Google Maps companies.",
                      "maximum_active_jobs_per_user": 1
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "GTMFree-Limits": {
                "$ref": "#/components/headers/Limits"
              },
              "GTMFree-Limits-Status": {
                "$ref": "#/components/headers/LimitsStatus"
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/RequestTimeout"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          }
        }
      }
    },
    "/tools/google-maps-scraper/jobs": {
      "post": {
        "operationId": "createGoogleMapsJob",
        "summary": "Submit a Google Maps geographic scraping job",
        "tags": [
          "Google Maps"
        ],
        "x-mcp-expose": true,
        "description": "Requires an enrolled, email-verified user. Each accepted POST creates a new job. One active job per user per tool across REST, MCP and SDKs. Returns 202 only when the worker confirms durable acceptance. After a timeout or disconnected response, list your jobs before submitting again. A busy tool returns 409 tool_busy with your active job ID. An uncertain worker acknowledgement returns 503 submission_outcome_unknown with error.job_id and retains the active slot; inspect that job instead of resubmitting. Exactly-once execution is not promised. RateLimit-Policy, RateLimit and GTMFree-Limits describe the applicable budgets, remaining allowances, admission costs and resets.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GoogleMapsJobRequest"
              },
              "example": {
                "parameters": {
                  "query": "dentists",
                  "region": "poland"
                },
                "exports": [
                  "json"
                ]
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Worker confirmed durable acceptance, or replay of a confirmed acceptance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobAccepted"
                },
                "example": {
                  "job_id": "job_example_01",
                  "status_url": "/api/v1/jobs/job_example_01",
                  "events_url": "/api/v1/jobs/job_example_01/events",
                  "results_url": "/api/v1/jobs/job_example_01/results"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Location": {
                "schema": {
                  "type": "string"
                },
                "example": "/api/v1/jobs/job_example_01"
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "example": 2
              },
              "Cache-Control": {
                "$ref": "#/components/headers/NoStore"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "GTMFree-Limits": {
                "$ref": "#/components/headers/Limits"
              },
              "GTMFree-Limits-Status": {
                "$ref": "#/components/headers/LimitsStatus"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/RequestTimeout"
          }
        }
      }
    },
    "/jobs": {
      "get": {
        "operationId": "listJobs",
        "summary": "List your jobs",
        "description": "Read only the authenticated owner’s gateway job records, newest first. This includes active jobs across REST, SDK, MCP and website entry points, so a disconnected client can recover its job IDs. No worker-wide listing is performed. Results and exports are excluded. Omit filters to include all retained job metadata; there is no guaranteed history-retention period. Listings use the last retained observations: inspect observed_at for freshness and use getJob when current worker state is needed. A well-formed but unsupported tool_id filter returns an empty page.",
        "tags": [
          "Jobs"
        ],
        "x-mcp-expose": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/PageLimit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "name": "tool_id",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/ToolId"
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/JobStatus"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of your retained jobs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobList"
                },
                "example": {
                  "items": [
                    {
                      "job_id": "job_example_01",
                      "tool_id": "google-maps-scraper",
                      "status": "queued",
                      "revision": 1,
                      "created_at": "2026-10-19T10:00:00Z",
                      "updated_at": "2026-10-19T10:00:00Z",
                      "started_at": null,
                      "completed_at": null,
                      "progress": {
                        "phase": "queued",
                        "unit": null,
                        "completed": 0,
                        "total": null
                      },
                      "result_available": false,
                      "error": null,
                      "observed_at": "2026-10-19T10:00:00Z"
                    }
                  ],
                  "next_cursor": null
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/NoStore"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "GTMFree-Limits": {
                "$ref": "#/components/headers/Limits"
              },
              "GTMFree-Limits-Status": {
                "$ref": "#/components/headers/LimitsStatus"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/RequestTimeout"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          }
        }
      }
    },
    "/jobs/{job_id}": {
      "parameters": [
        {
          "name": "job_id",
          "in": "path",
          "required": true,
          "schema": {
            "$ref": "#/components/schemas/JobId"
          },
          "description": "Public job ID previously returned to this user."
        }
      ],
      "get": {
        "operationId": "getJob",
        "summary": "Get job status and progress",
        "description": "Check ownership before access. Return status/progress without bulk results. One shared observer persists worker snapshots; reads never create a private worker connection per caller. Known nonterminal observations older than 15 seconds return 503, with an initial 15-second grace after acceptance; terminal states are retained locally. submission_unknown remains active pending operator reconciliation and has observed_at: null. Never fabricate a terminal state when a worker is unreachable. Nonterminal responses suggest a polling delay with Retry-After; terminal responses omit it.",
        "tags": [
          "Jobs"
        ],
        "x-mcp-expose": true,
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                },
                "example": {
                  "job_id": "job_example_01",
                  "tool_id": "google-maps-scraper",
                  "status": "queued",
                  "revision": 1,
                  "created_at": "2026-10-19T10:00:00Z",
                  "updated_at": "2026-10-19T10:00:00Z",
                  "started_at": null,
                  "completed_at": null,
                  "progress": {
                    "phase": "queued",
                    "unit": null,
                    "completed": 0,
                    "total": null
                  },
                  "result_available": false,
                  "error": null,
                  "observed_at": "2026-10-19T10:00:00Z"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/NoStore"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "GTMFree-Limits": {
                "$ref": "#/components/headers/Limits"
              },
              "GTMFree-Limits-Status": {
                "$ref": "#/components/headers/LimitsStatus"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/RequestTimeout"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          }
        }
      }
    },
    "/jobs/{job_id}/results": {
      "parameters": [
        {
          "name": "job_id",
          "in": "path",
          "required": true,
          "schema": {
            "$ref": "#/components/schemas/JobId"
          },
          "description": "Public job ID previously returned to this user."
        }
      ],
      "get": {
        "operationId": "getJobResults",
        "summary": "Read a page of Google Maps results",
        "description": "Check ownership before fetching or paging results. Read successful output or retained partial output from a failed job. A nonterminal job or a failed job with no retained result returns 409 result_not_available. If known output was removed, return 410 result_removed. A successful empty result is 200 with items: [], total: 0 and next_cursor: null. Results are immutable for a job; following a cursor never reruns scraping. Export descriptors replace worker base64; download bytes through the files endpoint. Pages are also bounded to 1 MiB and may contain fewer than limit items. A single record exceeding the JSON page budget returns 413 response_too_large; use a requested export instead. Cleanup normally removes retained output after seven days; this is best effort, without a retention SLA.",
        "tags": [
          "Jobs"
        ],
        "x-mcp-expose": false,
        "responses": {
          "200": {
            "description": "One page of successful or retained partial company records.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GoogleMapsJobResult"
                },
                "example": {
                  "job_id": "job_example_01",
                  "tool_id": "google-maps-scraper",
                  "status": "succeeded",
                  "partial": false,
                  "items": [
                    {
                      "name": "Example Dental Clinic",
                      "google_id": "example_google_id",
                      "url": "https://example.com",
                      "phone_number": null,
                      "gcid_list": [
                        "dentist"
                      ],
                      "coordinates": [
                        52.2297,
                        21.0122
                      ],
                      "address": {
                        "extra": null,
                        "way": "Example Street 1",
                        "postcode": "00-001",
                        "city": "Warsaw",
                        "country": "Poland"
                      },
                      "reviews": {
                        "amount": 12,
                        "average": 4.8
                      }
                    }
                  ],
                  "total": 1,
                  "next_cursor": null,
                  "cache": {
                    "mode": "resume",
                    "hit": false,
                    "complete": true,
                    "cached_at": "2026-10-19T10:05:00Z",
                    "expires_at": "2026-10-20T10:05:00Z"
                  },
                  "files": [
                    {
                      "format": "csv",
                      "filename": "results.csv",
                      "media_type": "text/csv; charset=utf-8",
                      "size_bytes": 240,
                      "download_url": "/api/v1/jobs/job_example_01/files/csv"
                    }
                  ]
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/NoStore"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "GTMFree-Limits": {
                "$ref": "#/components/headers/Limits"
              },
              "GTMFree-Limits-Status": {
                "$ref": "#/components/headers/LimitsStatus"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "410": {
            "$ref": "#/components/responses/ResultRemoved"
          },
          "408": {
            "$ref": "#/components/responses/RequestTimeout"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          }
        },
        "x-mcp-exposure-note": "Pagination bounds record count, not per-record bytes. A separate byte-bounded MCP projection is still required before tool exposure. Do not send base64 exports into agent context.",
        "parameters": [
          {
            "$ref": "#/components/parameters/PageLimit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ]
      }
    },
    "/jobs/{job_id}/files/{format}": {
      "parameters": [
        {
          "name": "job_id",
          "in": "path",
          "required": true,
          "schema": {
            "$ref": "#/components/schemas/JobId"
          },
          "description": "Public job ID previously returned to this user."
        },
        {
          "name": "format",
          "in": "path",
          "required": true,
          "schema": {
            "$ref": "#/components/schemas/ExportFormat"
          }
        }
      ],
      "get": {
        "operationId": "downloadJobFile",
        "summary": "Download a requested export",
        "description": "Authenticate and verify job ownership on every download. Return the requested, retained JSON/CSV/XLSX file as bytes with Content-Type: application/octet-stream and an attachment filename. The descriptor media_type identifies the file content. A single binary response type keeps generated SDKs from interpreting a JSON export as an API envelope. No base64 wrapper or redirect to a public URL. The format must have been requested at submission and produced by the worker; requesting a file never generates it or reruns scraping. Nonterminal output returns 409; an unrequested/unproduced format returns 404 file_not_found; previously retained but removed output returns 410 result_removed. Exports support up to 100,000 businesses and stream in bounded chunks from durable storage. Resume with a single HTTP Range: bytes=start-end or bytes=start- header (206); suffix and multipart ranges are rejected with 416. A normal GET streams the complete file. Every transfer is authenticated and charged for its requested raw byte count before streaming; interrupted/repeated bytes still consume the hourly allowance. Downloads have a 15-minute deadline and recheck authorization/network policy every 30 seconds. The default byte allowance is 4 GiB per user per UTC hour; connection and request limits remain enforced.",
        "tags": [
          "Jobs"
        ],
        "x-mcp-expose": false,
        "responses": {
          "200": {
            "description": "Export bytes with the media type matching format.",
            "headers": {
              "Content-Disposition": {
                "description": "Attachment name chosen from a fixed filename allowlist.",
                "schema": {
                  "type": "string"
                },
                "example": "attachment; filename=\"results.csv\""
              },
              "Content-Length": {
                "description": "Decoded file length in bytes.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/NoStore"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "GTMFree-Limits": {
                "$ref": "#/components/headers/Limits"
              },
              "GTMFree-Limits-Status": {
                "$ref": "#/components/headers/LimitsStatus"
              },
              "Link": {
                "description": "Link to the result page containing selected region and source/license notices.",
                "schema": {
                  "type": "string"
                }
              },
              "Accept-Ranges": {
                "schema": {
                  "type": "string",
                  "const": "bytes"
                }
              }
            },
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "410": {
            "$ref": "#/components/responses/ResultRemoved"
          },
          "422": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/RequestTimeout"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "206": {
            "description": "Requested inclusive byte range, streamed without loading the whole file.",
            "headers": {
              "Content-Disposition": {
                "description": "Attachment name chosen from a fixed filename allowlist.",
                "schema": {
                  "type": "string"
                },
                "example": "attachment; filename=\"results.csv\""
              },
              "Content-Length": {
                "description": "Decoded file length in bytes.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/NoStore"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "GTMFree-Limits": {
                "$ref": "#/components/headers/Limits"
              },
              "GTMFree-Limits-Status": {
                "$ref": "#/components/headers/LimitsStatus"
              },
              "Link": {
                "description": "Link to the result page containing selected region and source/license notices.",
                "schema": {
                  "type": "string"
                }
              },
              "Accept-Ranges": {
                "schema": {
                  "type": "string",
                  "const": "bytes"
                }
              },
              "Content-Range": {
                "schema": {
                  "type": "string"
                },
                "example": "bytes 131072-262143/409600"
              }
            },
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "416": {
            "description": "Malformed or unsatisfiable byte range. Use one explicit starting byte offset within the file.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_request",
                    "message": "Some request fields are invalid.",
                    "request_id": "req_example_01",
                    "job_id": null,
                    "issues": [
                      {
                        "location": "/parameters/query",
                        "message": "Provide a non-empty search phrase."
                      }
                    ]
                  }
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/NoStore"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "GTMFree-Limits": {
                "$ref": "#/components/headers/Limits"
              },
              "GTMFree-Limits-Status": {
                "$ref": "#/components/headers/LimitsStatus"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Range",
            "in": "header",
            "required": false,
            "description": "Optional single inclusive byte range; omit the end to read through EOF. Suffix and multipart ranges are unsupported.",
            "schema": {
              "type": "string",
              "pattern": "^bytes=[0-9]{1,12}-[0-9]{0,12}$"
            },
            "example": "bytes=131072-"
          }
        ]
      }
    },
    "/jobs/{job_id}/events": {
      "parameters": [
        {
          "name": "job_id",
          "in": "path",
          "required": true,
          "schema": {
            "$ref": "#/components/schemas/JobId"
          },
          "description": "Public job ID previously returned to this user."
        }
      ],
      "get": {
        "operationId": "watchJob",
        "summary": "Watch job status over SSE",
        "tags": [
          "Jobs"
        ],
        "x-mcp-expose": false,
        "description": "Authenticated SSE with status-only Job snapshots. Emit event: job, data: JSON Job, and id: gateway revision. Send the latest snapshot first, followed by changes, with idle heartbeat comments; close after a terminal snapshot. Reconnect sends the latest snapshot, not historical replay. Last-Event-ID is only a hint. Disconnect never cancels backend execution or releases the active slot. Use the Authorization header; query-string credentials are not supported. MCP uses its own negotiated progress/task mechanisms instead of treating this REST SSE endpoint as a tool. Send heartbeat comments at least every 15 seconds. If an error occurs after headers are sent, emit event: error with a sanitized Error JSON envelope and close; HTTP status cannot change at that point. A connection ending without a terminal snapshot does not prove completion. Revalidate authorization and local network policy every 30 seconds; revoked or banned access closes the stream. Native browser EventSource cannot attach a Bearer header; use an authenticated streaming client or polling. Never put an API key in a URL. Streams are limited to 32 globally, six per user and two per job, and close after 15 minutes. Reconnect or poll to continue.",
        "parameters": [
          {
            "name": "Last-Event-ID",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]+$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "UTF-8 SSE stream; an already terminal job emits one snapshot then closes.",
            "headers": {
              "Cache-Control": {
                "$ref": "#/components/headers/NoStore"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "GTMFree-Limits": {
                "$ref": "#/components/headers/Limits"
              },
              "GTMFree-Limits-Status": {
                "$ref": "#/components/headers/LimitsStatus"
              }
            },
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                },
                "example": "id: 1\nevent: job\ndata: {\"job_id\":\"job_example_01\",\"tool_id\":\"google-maps-scraper\",\"status\":\"queued\",\"revision\":1,\"created_at\":\"2026-10-19T10:00:00Z\",\"updated_at\":\"2026-10-19T10:00:00Z\",\"started_at\":null,\"completed_at\":null,\"progress\":{\"phase\":\"queued\",\"unit\":null,\"completed\":0,\"total\":null},\"result_available\":false,\"error\":null,\"observed_at\":\"2026-10-19T10:00:00Z\"}\n\n"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/RequestTimeout"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          }
        }
      }
    },
    "/regions": {
      "get": {
        "tags": [
          "Regions"
        ],
        "operationId": "discoverRegions",
        "summary": "Discover countries and administrative areas",
        "description": "Authenticated geographic discovery; creates no scraping job. Start without load to inspect supported_levels and loaded_levels. load=true explicitly loads one selected country/level; a cold lookup can return 503 region_loading while work continues. Retry the same lookup, or use load=false once indexing completes. Global searches cover only loaded subdivisions (scope=loaded, complete=false). Use exact returned IDs; never construct them. Country-specific supported_levels are authoritative. Query booleans are true/false. Shared request, region lookup and daily load limits apply across REST and MCP. Use kind=city for the worldwide local GeoNames city catalog, including Munich and Lyon. Load one exact returned city ID with load=true; preview=true requires an ID and returns simplified display geometry. City boundary_status is explicit. Municipal polygons are not substituted with points, boxes or larger regions. City scope=cities and complete=true mean the gazetteer snapshot was searched, not universal polygon coverage. Preserve GeoNames and OSM attribution.",
        "x-mcp-expose": true,
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128,
              "pattern": "\\S"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128,
              "pattern": "\\S"
            }
          },
          {
            "name": "level",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 5
            }
          },
          {
            "name": "parent_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/GoogleMapsWorkerRegionId"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/GoogleMapsWorkerRegionId"
            }
          },
          {
            "name": "load",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100000,
              "default": 0
            }
          },
          {
            "in": "query",
            "name": "kind",
            "schema": {
              "type": "string",
              "enum": [
                "administrative",
                "city"
              ],
              "default": "administrative"
            }
          },
          {
            "in": "query",
            "name": "preview",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Region discovery. complete=false means the requested layer is not loaded, or a global search covers only already-loaded subdivisions. Preserve attribution and scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GoogleMapsWorkerDiscoverRegionsResponse"
                }
              }
            },
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/NoStore"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "GTMFree-Limits": {
                "$ref": "#/components/headers/Limits"
              },
              "GTMFree-Limits-Status": {
                "$ref": "#/components/headers/LimitsStatus"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable",
            "description": "Temporary unavailability or region_loading. Cold metadata/boundary loading continues in the worker; retry this lookup after Retry-After. No scraping job was created."
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "408": {
            "$ref": "#/components/responses/RequestTimeout"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyBearer": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "gtm:free API key",
        "description": "Authorization: Bearer <API key>. Validate the hashed opaque key and its enrolled, verified, non-banned owner on every request. WorkOS server secrets are never client credentials. MCP OAuth and website HttpOnly sessions are configured separately."
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing, invalid or revoked API key. Includes a Bearer challenge.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "invalid_api_key",
                "message": "Supply a valid gtm:free API key.",
                "request_id": "req_example_01",
                "job_id": null,
                "issues": []
              }
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "WWW-Authenticate": {
            "schema": {
              "type": "string"
            },
            "example": "Bearer realm=\"gtmfree\""
          },
          "Cache-Control": {
            "$ref": "#/components/headers/NoStore"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "GTMFree-Limits": {
            "$ref": "#/components/headers/Limits"
          },
          "GTMFree-Limits-Status": {
            "$ref": "#/components/headers/LimitsStatus"
          }
        }
      },
      "Forbidden": {
        "description": "Verified owner is banned or fails network policy. A previously enrolled user whose email is no longer verified is also denied. Missing/invalid/revoked keys and non-enrolled owners are 401. The edge may return a non-JSON 403 page.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "account_banned",
                "message": "Your account is suspended.",
                "request_id": "req_example_01",
                "job_id": null,
                "issues": []
              }
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Cache-Control": {
            "$ref": "#/components/headers/NoStore"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "GTMFree-Limits": {
            "$ref": "#/components/headers/Limits"
          },
          "GTMFree-Limits-Status": {
            "$ref": "#/components/headers/LimitsStatus"
          }
        }
      },
      "NotFound": {
        "description": "No accessible job or requested export. Another user’s job/file is indistinguishable from an unknown ID. A format that was not requested or produced also returns 404.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "job_not_found",
                "message": "No accessible job has this ID.",
                "request_id": "req_example_01",
                "job_id": null,
                "issues": []
              }
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Cache-Control": {
            "$ref": "#/components/headers/NoStore"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "GTMFree-Limits": {
            "$ref": "#/components/headers/Limits"
          },
          "GTMFree-Limits-Status": {
            "$ref": "#/components/headers/LimitsStatus"
          }
        }
      },
      "Conflict": {
        "description": "This tool already has an active job for this user, or results are not available yet.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "tool_busy",
                "message": "You already have an active job for this tool.",
                "request_id": "req_example_01",
                "job_id": "job_example_01",
                "issues": []
              }
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Cache-Control": {
            "$ref": "#/components/headers/NoStore"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "GTMFree-Limits": {
            "$ref": "#/components/headers/Limits"
          },
          "GTMFree-Limits-Status": {
            "$ref": "#/components/headers/LimitsStatus"
          }
        }
      },
      "InvalidRequest": {
        "description": "Invalid request fields. No new worker job was submitted.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "invalid_request",
                "message": "Some request fields are invalid.",
                "request_id": "req_example_01",
                "job_id": null,
                "issues": [
                  {
                    "location": "/parameters/query",
                    "message": "Provide a non-empty search phrase."
                  }
                ]
              }
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Cache-Control": {
            "$ref": "#/components/headers/NoStore"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "GTMFree-Limits": {
            "$ref": "#/components/headers/Limits"
          },
          "GTMFree-Limits-Status": {
            "$ref": "#/components/headers/LimitsStatus"
          }
        }
      },
      "TooLarge": {
        "description": "Input exceeds configured request/frame limits or the requested JSON result record exceeds the response byte budget. Returns request_too_large or response_too_large. Reading an oversized record does not submit new work.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "request_too_large",
                "message": "The request exceeds the configured limit.",
                "request_id": "req_example_01",
                "job_id": null,
                "issues": []
              }
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Cache-Control": {
            "$ref": "#/components/headers/NoStore"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "GTMFree-Limits": {
            "$ref": "#/components/headers/Limits"
          },
          "GTMFree-Limits-Status": {
            "$ref": "#/components/headers/LimitsStatus"
          }
        }
      },
      "RateLimited": {
        "description": "Request rate, submission-attempt or user work/download budget exceeded. Returns rate_limited or quota_exceeded with Retry-After. Key rotation does not reset user budgets.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "rate_limited",
                "message": "Too many requests. Try again after the suggested delay.",
                "request_id": "req_example_01",
                "job_id": null,
                "issues": []
              }
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          },
          "Cache-Control": {
            "$ref": "#/components/headers/NoStore"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "GTMFree-Limits": {
            "$ref": "#/components/headers/Limits"
          },
          "GTMFree-Limits-Status": {
            "$ref": "#/components/headers/LimitsStatus"
          }
        }
      },
      "Unavailable": {
        "description": "Service unavailable, submissions paused, capacity exhausted, or worker acceptance not confirmed. If error.job_id is present, inspect that job or list your jobs before submitting again. Honor Retry-After; it is not an instruction to repeat a submission.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "submission_outcome_unknown",
                "message": "The worker acceptance could not be confirmed. Inspect this job; do not submit a new job.",
                "request_id": "req_example_01",
                "job_id": "job_example_01",
                "issues": []
              }
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          },
          "Cache-Control": {
            "$ref": "#/components/headers/NoStore"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "GTMFree-Limits": {
            "$ref": "#/components/headers/Limits"
          },
          "GTMFree-Limits-Status": {
            "$ref": "#/components/headers/LimitsStatus"
          }
        }
      },
      "InternalError": {
        "description": "Unexpected gateway failure. Use the correlation ID when reporting it.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "internal_error",
                "message": "Unable to complete this request.",
                "request_id": "req_example_01",
                "job_id": null,
                "issues": []
              }
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Cache-Control": {
            "$ref": "#/components/headers/NoStore"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "GTMFree-Limits": {
            "$ref": "#/components/headers/Limits"
          },
          "GTMFree-Limits-Status": {
            "$ref": "#/components/headers/LimitsStatus"
          }
        }
      },
      "BadRequest": {
        "description": "Malformed JSON, invalid/mismatched cursor, or another malformed HTTP request. No new worker job was dispatched.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "invalid_cursor",
                "message": "The cursor is malformed or does not match these filters.",
                "request_id": "req_example_01",
                "job_id": null,
                "issues": []
              }
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Cache-Control": {
            "$ref": "#/components/headers/NoStore"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "GTMFree-Limits": {
            "$ref": "#/components/headers/Limits"
          },
          "GTMFree-Limits-Status": {
            "$ref": "#/components/headers/LimitsStatus"
          }
        }
      },
      "ResultRemoved": {
        "description": "Known job output was removed; fetching it never reruns the job.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "result_removed",
                "message": "This job output is no longer retained.",
                "request_id": "req_example_01",
                "job_id": "job_example_01",
                "issues": []
              }
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Cache-Control": {
            "$ref": "#/components/headers/NoStore"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "GTMFree-Limits": {
            "$ref": "#/components/headers/Limits"
          },
          "GTMFree-Limits-Status": {
            "$ref": "#/components/headers/LimitsStatus"
          }
        }
      },
      "RequestTimeout": {
        "description": "The request body did not complete within its absolute ten-second deadline.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "request_timeout",
                "message": "The request did not complete in time.",
                "request_id": "req_example_01",
                "job_id": null,
                "issues": []
              }
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Cache-Control": {
            "$ref": "#/components/headers/NoStore"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "GTMFree-Limits": {
            "$ref": "#/components/headers/Limits"
          },
          "GTMFree-Limits-Status": {
            "$ref": "#/components/headers/LimitsStatus"
          }
        }
      }
    },
    "schemas": {
      "JobId": {
        "type": "string",
        "description": "Opaque public gateway job ID; never a worker address or filesystem path.",
        "pattern": "^job_[A-Za-z0-9_-]+$"
      },
      "Tool": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "name",
          "availability",
          "description",
          "maximum_active_jobs_per_user"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/ToolId"
          },
          "name": {
            "type": "string"
          },
          "availability": {
            "type": "string",
            "enum": [
              "available",
              "unavailable"
            ],
            "description": "Whether the documented tool is enabled. Available does not guarantee immediate capacity."
          },
          "description": {
            "type": "string"
          },
          "maximum_active_jobs_per_user": {
            "type": "integer",
            "const": 1
          }
        }
      },
      "ToolList": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Tool"
            }
          }
        }
      },
      "GoogleMapsJobRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "parameters"
        ],
        "properties": {
          "parameters": {
            "$ref": "#/components/schemas/GoogleMapsWorkerScrapeRequest"
          },
          "exports": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExportFormat"
            },
            "uniqueItems": true,
            "default": [],
            "maxItems": 3
          }
        },
        "description": "Geographic scraping only. The gateway sets the private worker kind=scrape and injects a private, user-isolated cache namespace. Credentials, socket paths and filesystem paths are never public inputs. Requested formats are a set. Omitting exports produces typed JSON result pages but no downloadable export files."
      },
      "JobAccepted": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "job_id",
          "status_url",
          "events_url",
          "results_url"
        ],
        "properties": {
          "job_id": {
            "$ref": "#/components/schemas/JobId"
          },
          "status_url": {
            "type": "string",
            "pattern": "^/api/v1/jobs/job_[A-Za-z0-9_-]+$"
          },
          "events_url": {
            "type": "string",
            "pattern": "^/api/v1/jobs/job_[A-Za-z0-9_-]+/events$"
          },
          "results_url": {
            "type": "string",
            "pattern": "^/api/v1/jobs/job_[A-Za-z0-9_-]+/results$"
          }
        }
      },
      "Issue": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "location",
          "message"
        ],
        "properties": {
          "location": {
            "type": "string",
            "description": "JSON Pointer to an invalid request field, without echoing its value."
          },
          "message": {
            "type": "string"
          }
        }
      },
      "JobFailure": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "code",
          "message",
          "issues"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable machine-readable failure code; new codes may be added. coverage_incomplete indicates unresolved sampling uncertainty; resource_limit can indicate a coverage budget stop. Retained output stays available on failed jobs."
          },
          "message": {
            "type": "string",
            "description": "Sanitized message without credentials, stack traces, worker IDs or storage paths."
          },
          "issues": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Issue"
            }
          },
          "matches": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "$ref": "#/components/schemas/GoogleMapsWorkerRegionRecord"
            },
            "description": "Select a returned opaque ID explicitly. Ambiguous names are never resolved by choosing the first result."
          }
        }
      },
      "Error": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "code",
              "message",
              "request_id",
              "job_id",
              "issues"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable machine-readable code. Core codes: invalid_api_key, email_not_verified, account_banned, country_not_allowed, blocked_ip, blocked_asn, invalid_client_ip, tool_busy, submission_in_progress, submission_outcome_unknown, job_not_found, file_not_found, result_not_available, result_removed, invalid_request, invalid_cursor, request_too_large, rate_limited, service_unavailable, authentication_unavailable, network_data_unavailable, internal_error. Clients must tolerate new codes."
              },
              "message": {
                "type": "string"
              },
              "request_id": {
                "type": "string",
                "description": "Support correlation ID, never a credential."
              },
              "job_id": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/JobId"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "An owned active/conflicting/uncertain job when known; null when no owned job applies. Never another user’s ID."
              },
              "issues": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Issue"
                }
              },
              "matches": {
                "type": "array",
                "maxItems": 20,
                "items": {
                  "$ref": "#/components/schemas/GoogleMapsWorkerRegionRecord"
                },
                "description": "Select a returned opaque ID explicitly. Ambiguous names are never resolved by choosing the first result."
              }
            }
          }
        }
      },
      "Job": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "job_id",
          "tool_id",
          "status",
          "revision",
          "created_at",
          "updated_at",
          "started_at",
          "completed_at",
          "progress",
          "result_available",
          "error",
          "observed_at"
        ],
        "properties": {
          "job_id": {
            "$ref": "#/components/schemas/JobId"
          },
          "tool_id": {
            "$ref": "#/components/schemas/ToolId"
          },
          "status": {
            "$ref": "#/components/schemas/JobStatus"
          },
          "revision": {
            "type": "integer",
            "minimum": 1,
            "description": "Gateway-owned monotonically increasing revision, distinct from the private worker revision."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "progress": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/JobProgress"
              },
              {
                "type": "null"
              }
            ]
          },
          "result_available": {
            "type": "boolean"
          },
          "error": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/JobFailure"
              },
              {
                "type": "null"
              }
            ]
          },
          "observed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Time of the last successful worker snapshot read; null before observation. Distinct from updated_at, which records a public state change."
          },
          "coverage": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCoverageEvidence",
            "description": "Optional server-owned sampling evidence, preserved for terminal results and cache hits. Omitted for older results. Sampling completion does not guarantee exhaustive inventory; pending counts are lower bounds."
          }
        },
        "description": "Status-only projection. Bulk data and exports live in the results operation. submitting and submission_unknown occupy the active slot. A disconnect or timeout never proves execution stopped. Only succeeded and failed are terminal. Unknown admission has null progress; worker-unreachable status reads return 503 rather than fabricating progress."
      },
      "GoogleMapsJobResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "job_id",
          "tool_id",
          "status",
          "partial",
          "items",
          "total",
          "next_cursor",
          "cache",
          "files"
        ],
        "properties": {
          "job_id": {
            "$ref": "#/components/schemas/JobId"
          },
          "tool_id": {
            "type": "string",
            "const": "google-maps-scraper"
          },
          "status": {
            "type": "string",
            "enum": [
              "succeeded",
              "failed"
            ]
          },
          "partial": {
            "type": "boolean",
            "description": "True exactly when retained output belongs to a failed job; false for successful output, including an empty result."
          },
          "items": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/GoogleMapsWorkerCompanyRecord"
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "Total retained company records for this immutable job result, not just this page.",
            "maximum": 100000
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Bound to this owner, job and immutable result revision; null ends the result.",
            "minLength": 1,
            "maxLength": 2048
          },
          "cache": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCacheReceipt"
          },
          "files": {
            "type": "array",
            "maxItems": 3,
            "items": {
              "$ref": "#/components/schemas/ExportFile"
            }
          },
          "region": {
            "$ref": "#/components/schemas/GoogleMapsWorkerRegionRecord",
            "description": "Exact selected administrative area and original geoBoundaries source/license notices. Present for structured selections, including cache hits; omitted for older results and custom GeoJSON."
          },
          "coverage": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCoverageEvidence",
            "description": "Optional server-owned sampling evidence, preserved for terminal results and cache hits. Omitted for older results. Sampling completion does not guarantee exhaustive inventory; pending counts are lower bounds."
          }
        },
        "description": "One page of an immutable terminal job result. Preserve worker record order within this job; no ordering across separate jobs is promised. Files and the cache receipt describe the complete retained result on every page. Retrieving output never starts new work. Jobs retain up to 100,000 businesses; follow every next_cursor to retrieve all records. Pages and MCP chunks remain byte-bounded."
      },
      "ToolId": {
        "type": "string",
        "minLength": 1,
        "maxLength": 64,
        "pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$",
        "examples": [
          "google-maps-scraper"
        ],
        "description": "Stable public tool identifier. Treat it as an opaque string so adding another supported tool does not require an SDK enum update. Only Google Maps is in this contract iteration."
      },
      "JobStatus": {
        "type": "string",
        "enum": [
          "submitting",
          "submission_unknown",
          "queued",
          "running",
          "succeeded",
          "failed"
        ],
        "description": "submitting, submission_unknown, queued and running occupy the user/tool slot. Only succeeded and failed are terminal."
      },
      "JobList": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "items",
          "next_cursor"
        ],
        "properties": {
          "items": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/Job"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass this opaque cursor to fetch the next page; null ends the list.",
            "minLength": 1,
            "maxLength": 2048
          }
        },
        "description": "Owned gateway jobs, newest first by (created_at, job_id). Filters are not a transactional snapshot: running jobs can change status between pages."
      },
      "CurrentUser": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "user_id",
          "email",
          "email_verified",
          "limits"
        ],
        "properties": {
          "user_id": {
            "type": "string",
            "format": "uuid",
            "description": "Stable local user ID; never a WorkOS credential or API key."
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "email_verified": {
            "type": "boolean",
            "const": true
          },
          "limits": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "maximum_active_jobs_per_tool"
            ],
            "properties": {
              "maximum_active_jobs_per_tool": {
                "type": "integer",
                "const": 1
              }
            }
          }
        },
        "description": "The verified, enrolled, non-banned owner of the current API key. No key secret is returned."
      },
      "ExportFormat": {
        "type": "string",
        "enum": [
          "json",
          "csv",
          "xlsx"
        ]
      },
      "ExportFile": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "format",
          "filename",
          "media_type",
          "size_bytes",
          "download_url"
        ],
        "properties": {
          "format": {
            "$ref": "#/components/schemas/ExportFormat"
          },
          "filename": {
            "type": "string",
            "enum": [
              "results.json",
              "results.csv",
              "results.xlsx"
            ]
          },
          "media_type": {
            "type": "string",
            "enum": [
              "application/json",
              "text/csv; charset=utf-8",
              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
            ],
            "description": "Media type of the file content. The download endpoint transports all formats as application/octet-stream with a fixed attachment filename."
          },
          "size_bytes": {
            "type": "integer",
            "minimum": 0
          },
          "download_url": {
            "type": "string",
            "pattern": "^/api/v1/jobs/job_[A-Za-z0-9_-]+/files/(json|csv|xlsx)$",
            "description": "Same-origin, authenticated URL. Supply the same Bearer API key; this is not a public or signed download link."
          }
        },
        "description": "Only exports requested at submission and retained by the worker are listed. REST transports binary downloads; MCP getJobExport returns bounded base64 chunks of the same immutable file."
      },
      "JobProgress": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "phase",
          "unit",
          "completed",
          "total"
        ],
        "properties": {
          "phase": {
            "type": "string",
            "minLength": 1,
            "description": "Tool-specific phase. Google Maps currently uses queued, preparing, searching, exporting, completed and failed; clients must tolerate other phases.",
            "maxLength": 64
          },
          "unit": {
            "type": [
              "string",
              "null"
            ],
            "description": "Unit counted by completed/total, for example points for Maps. Null means not determined. Other tools may use other units.",
            "maxLength": 32
          },
          "completed": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "total": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Null while further sampling work can be generated. Pending coverage counts are lower bounds; do not derive a completion percentage from them."
          }
        },
        "description": "Progress counts reported by the tool, not a completion percentage. completed counts finished units, including failed or partial searches; it does not certify complete coverage. total and unit can remain null while unknown. completed must not exceed a known total. Preserve counters during export."
      },
      "RegionMatches": {
        "type": "array",
        "maxItems": 20,
        "items": {
          "$ref": "#/components/schemas/GoogleMapsWorkerRegionRecord"
        },
        "description": "Select a returned opaque ID explicitly. Ambiguous names are never resolved by choosing the first result."
      },
      "GoogleMapsWorkerAddress": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "extra": {
            "$ref": "#/components/schemas/GoogleMapsWorkerNullableString"
          },
          "way": {
            "$ref": "#/components/schemas/GoogleMapsWorkerNullableString"
          },
          "postcode": {
            "$ref": "#/components/schemas/GoogleMapsWorkerNullableString"
          },
          "city": {
            "$ref": "#/components/schemas/GoogleMapsWorkerNullableString"
          },
          "country": {
            "$ref": "#/components/schemas/GoogleMapsWorkerNullableString"
          }
        },
        "default": {
          "extra": null,
          "way": null,
          "postcode": null,
          "city": null,
          "country": null
        }
      },
      "GoogleMapsWorkerBoundaryCollection": {
        "type": "object",
        "required": [
          "type",
          "features"
        ],
        "properties": {
          "type": {
            "const": "FeatureCollection"
          },
          "features": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "required": [
                "type",
                "geometry"
              ],
              "properties": {
                "type": {
                  "const": "Feature"
                },
                "properties": {
                  "type": [
                    "object",
                    "null"
                  ]
                },
                "geometry": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/GoogleMapsWorkerPolygon"
                    },
                    {
                      "$ref": "#/components/schemas/GoogleMapsWorkerMultiPolygon"
                    }
                  ]
                }
              }
            }
          }
        },
        "description": "Nonempty valid polygon features; invalid geometry or non-WGS84 data is rejected before searches."
      },
      "GoogleMapsWorkerCacheOptions": {
        "type": "object",
        "additionalProperties": false,
        "description": "Select cache reuse behavior. The gateway always chooses a private, user-scoped namespace; clients cannot supply a namespace or filesystem path. Omission uses resume.",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "resume",
              "refresh",
              "disabled"
            ],
            "default": "resume",
            "description": "For scraping, resume reuses complete query results for 24 hours from completion, without extending expiration on a hit. After expiration, searches run again rather than reusing expired checkpoints. Incomplete point searches are not checkpointed or promoted to complete query results. Interrupted complete checkpoints can be resumed for up to 24 hours. Resolution candidate-cache behavior is unchanged. refresh\nignores prior checkpoints, replaces them with fresh searches, and\nsaves new results. disabled neither reads nor writes run data.\nGeographic download caches are independent of this mode.\n"
          }
        }
      },
      "GoogleMapsWorkerCacheReceipt": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "mode"
        ],
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "resume",
              "refresh",
              "disabled"
            ]
          },
          "hit": {
            "type": "boolean",
            "description": "Scraping only. True when a completed query result was reused within 24 hours."
          },
          "complete": {
            "type": "boolean",
            "description": "Scraping only. False for retained partial results on failed jobs. Such results are not cached as complete."
          },
          "cached_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Scraping only. Time the complete result was cached; null for bypassed or incomplete results."
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Scraping only. Exactly 24 hours after cached_at; cache hits do not extend this deadline."
          }
        },
        "description": "Cache receipt with the private worker namespace removed."
      },
      "GoogleMapsWorkerCityCatalogCoverage": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "dataset",
          "snapshot",
          "cities",
          "countries",
          "boundary_coverage",
          "loaded_boundaries"
        ],
        "properties": {
          "dataset": {
            "const": "GeoNames cities15000"
          },
          "snapshot": {
            "type": "string"
          },
          "cities": {
            "type": "integer",
            "minimum": 0
          },
          "countries": {
            "type": "integer",
            "minimum": 0
          },
          "boundary_coverage": {
            "const": "on_demand_not_guaranteed"
          },
          "loaded_boundaries": {
            "type": "integer",
            "minimum": 0
          }
        },
        "description": "Complete means this gazetteer snapshot was searched, not that every world city or every city boundary is available. The dataset covers populated places above 15,000 inhabitants plus capitals, not a fixed top-N ranking."
      },
      "GoogleMapsWorkerCityEvidence": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "geonames_id",
          "population",
          "feature_code",
          "parent_names",
          "gazetteer_source",
          "aliases_truncated",
          "boundary_status",
          "boundary_reason",
          "osm_relation_id",
          "osm_admin_level"
        ],
        "properties": {
          "geonames_id": {
            "type": "integer",
            "minimum": 1
          },
          "population": {
            "type": "integer",
            "minimum": 0
          },
          "feature_code": {
            "type": "string"
          },
          "parent_names": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "gazetteer_source": {
            "$ref": "#/components/schemas/GoogleMapsWorkerRegionAttribution"
          },
          "aliases_truncated": {
            "type": "boolean"
          },
          "boundary_status": {
            "enum": [
              "not_loaded",
              "available",
              "unavailable",
              "ambiguous",
              "provider_error",
              "resource_limit"
            ]
          },
          "boundary_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "osm_relation_id": {
            "type": [
              "integer",
              "null"
            ]
          },
          "osm_admin_level": {
            "type": [
              "integer",
              "null"
            ]
          }
        }
      },
      "GoogleMapsWorkerCompany": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "name": {
            "$ref": "#/components/schemas/GoogleMapsWorkerNullableString"
          },
          "google_id": {
            "$ref": "#/components/schemas/GoogleMapsWorkerNullableString"
          },
          "url": {
            "$ref": "#/components/schemas/GoogleMapsWorkerNullableString"
          },
          "phone_number": {
            "$ref": "#/components/schemas/GoogleMapsWorkerNullableString"
          },
          "gcid_list": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "default": []
          },
          "coordinates": {
            "type": "array",
            "items": {
              "type": [
                "number",
                "null"
              ]
            },
            "default": [
              null,
              null
            ],
            "description": "Extracted records contain [latitude, longitude], with nulls for\nmissing values. Export input also accepts other lengths, matching\nthe original model; only the first two elements are exported.\n"
          },
          "address": {
            "$ref": "#/components/schemas/GoogleMapsWorkerAddress"
          },
          "reviews": {
            "$ref": "#/components/schemas/GoogleMapsWorkerReviews"
          }
        },
        "description": "Original Company fields, with original null/default behavior. Export\ninput may omit fields; output records always include all Company,\nAddress and Reviews fields with defaults filled. Strings are not\nconstrained to URI/phone formats. No invented missing-field values.\n"
      },
      "GoogleMapsWorkerCompanyRecord": {
        "description": "Fully populated output form of the source Company model.",
        "allOf": [
          {
            "$ref": "#/components/schemas/GoogleMapsWorkerCompany"
          },
          {
            "type": "object",
            "required": [
              "name",
              "google_id",
              "url",
              "phone_number",
              "gcid_list",
              "coordinates",
              "address",
              "reviews"
            ],
            "properties": {
              "coordinates": {
                "minItems": 2,
                "maxItems": 2
              },
              "address": {
                "required": [
                  "extra",
                  "way",
                  "postcode",
                  "city",
                  "country"
                ]
              },
              "reviews": {
                "required": [
                  "amount",
                  "average"
                ]
              }
            }
          }
        ]
      },
      "GoogleMapsWorkerCountryCoverage": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "country",
          "supported_levels",
          "loaded_levels"
        ],
        "properties": {
          "country": {
            "$ref": "#/components/schemas/GoogleMapsWorkerRegionRecord"
          },
          "supported_levels": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GoogleMapsWorkerRegionLevel"
            }
          },
          "loaded_levels": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 0,
              "maximum": 5
            }
          }
        }
      },
      "GoogleMapsWorkerCoverageCount": {
        "type": "integer",
        "minimum": 0
      },
      "GoogleMapsWorkerCoverageEvidence": {
        "type": "object",
        "additionalProperties": false,
        "description": "Server-owned sampling evidence. Present for adaptive scrape results, including partial failed jobs and cache hits. Sampling completion never guarantees exhaustive Google inventory. Pending counts are a lower bound because finer tiles are generated lazily. No execution controls are accepted from public callers. Keep this metadata alongside paged artifacts.",
        "required": [
          "policy",
          "status",
          "sampling_complete",
          "exhaustive",
          "stopping_reason",
          "baseline_spacing_km",
          "minimum_spacing_km",
          "initial_spacing_km",
          "points_completed",
          "points_pending",
          "pending_is_lower_bound",
          "baseline_tiles_completed",
          "offset_views_completed",
          "points_attempted_this_run",
          "points_reused",
          "google_requests_this_run",
          "google_requests_total",
          "pages",
          "full_pages",
          "truncated_views",
          "unresolved_leaves",
          "unique_records",
          "elapsed_seconds",
          "decisions",
          "resumable",
          "language",
          "country"
        ],
        "properties": {
          "policy": {
            "enum": [
              "coverage-v2",
              "coverage-v3"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "sampled",
              "partial"
            ]
          },
          "sampling_complete": {
            "type": "boolean"
          },
          "exhaustive": {
            "const": false
          },
          "stopping_reason": {
            "type": "string",
            "maxLength": 64
          },
          "baseline_spacing_km": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "Maximum nominal stable leaf scale for coverage-v3. Smaller cells are explored where observations change or reveal new IDs. This is a heuristic stopping scale, not an exhaustive inventory guarantee."
          },
          "minimum_spacing_km": {
            "type": "number",
            "exclusiveMinimum": 0
          },
          "initial_spacing_km": {
            "type": "number",
            "minimum": 0
          },
          "points_completed": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCoverageCount"
          },
          "points_pending": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCoverageCount"
          },
          "pending_is_lower_bound": {
            "const": true
          },
          "baseline_tiles_completed": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCoverageCount"
          },
          "offset_views_completed": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCoverageCount"
          },
          "points_attempted_this_run": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCoverageCount"
          },
          "points_reused": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCoverageCount"
          },
          "google_requests_this_run": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCoverageCount"
          },
          "google_requests_total": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCoverageCount"
          },
          "pages": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCoverageCount"
          },
          "full_pages": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCoverageCount"
          },
          "truncated_views": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCoverageCount"
          },
          "unresolved_leaves": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCoverageCount"
          },
          "unique_records": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCoverageCount"
          },
          "elapsed_seconds": {
            "type": "number",
            "minimum": 0
          },
          "decisions": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/GoogleMapsWorkerCoverageCount"
            }
          },
          "resumable": {
            "type": "boolean"
          },
          "language": {
            "type": "string"
          },
          "country": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "GoogleMapsWorkerCustomGeodata": {
        "type": "object",
        "additionalProperties": false,
        "minProperties": 1,
        "description": "Optional per-call replacements for the existing countries/<region> and\ngmaps/<region> GeoJSON files. Omitted pieces use deployment-provided\nregional files or auto-download generation. Coordinates are WGS84\nlongitude,latitude. Preserve feature and seed order, including duplicate\nseeds. Custom inputs do not override the source country-name filter.\n",
        "properties": {
          "boundary": {
            "$ref": "#/components/schemas/GoogleMapsWorkerBoundaryCollection"
          },
          "seed_cities": {
            "$ref": "#/components/schemas/GoogleMapsWorkerSeedCollection"
          }
        }
      },
      "GoogleMapsWorkerDiscoverRegionsRequest": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "administrative",
              "city"
            ],
            "default": "administrative",
            "description": "City discovery searches the global GeoNames gazetteer locally; administrative discovery retains country/level behavior. City IDs imply city kind."
          },
          "preview": {
            "type": "boolean",
            "default": false,
            "description": "Include a bounded simplified map preview for an exact ID. Previews never replace the full geometry used for scraping."
          },
          "country": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "\\S"
          },
          "query": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "\\S"
          },
          "level": {
            "type": "integer",
            "minimum": 0,
            "maximum": 5
          },
          "parent_id": {
            "$ref": "#/components/schemas/GoogleMapsWorkerRegionId"
          },
          "id": {
            "$ref": "#/components/schemas/GoogleMapsWorkerRegionId"
          },
          "load": {
            "type": "boolean",
            "default": false
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "default": 50
          },
          "offset": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100000,
            "default": 0
          }
        },
        "allOf": [
          {
            "if": {
              "required": [
                "preview"
              ],
              "properties": {
                "preview": {
                  "const": true
                }
              }
            },
            "then": {
              "required": [
                "id"
              ]
            }
          }
        ]
      },
      "GoogleMapsWorkerDiscoverRegionsResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "source",
          "attribution",
          "items",
          "countries",
          "next_offset",
          "scope",
          "complete"
        ],
        "properties": {
          "source": {
            "enum": [
              "geoBoundaries gbOpen",
              "GeoNames cities15000"
            ]
          },
          "attribution": {
            "$ref": "#/components/schemas/GoogleMapsWorkerRegionAttribution"
          },
          "items": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/GoogleMapsWorkerRegionRecord"
            }
          },
          "countries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GoogleMapsWorkerCountryCoverage"
            }
          },
          "next_offset": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "scope": {
            "type": "string",
            "enum": [
              "countries",
              "country",
              "loaded",
              "cities"
            ]
          },
          "city_catalog": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCityCatalogCoverage"
          },
          "complete": {
            "type": "boolean",
            "description": "Whether the requested country/level or country catalog was fully searched. Global subdivision search is limited to cached levels and always reports false."
          }
        }
      },
      "GoogleMapsWorkerLinearRing": {
        "type": "array",
        "minItems": 4,
        "items": {
          "$ref": "#/components/schemas/GoogleMapsWorkerPosition"
        },
        "description": "First and last positions must be equal; additional geometry validation is performed at runtime."
      },
      "GoogleMapsWorkerMultiPolygon": {
        "type": "object",
        "required": [
          "type",
          "coordinates"
        ],
        "properties": {
          "type": {
            "const": "MultiPolygon"
          },
          "coordinates": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/GoogleMapsWorkerPolygonCoordinates"
            }
          }
        }
      },
      "GoogleMapsWorkerNullableString": {
        "type": [
          "string",
          "null"
        ],
        "default": null
      },
      "GoogleMapsWorkerPolygon": {
        "type": "object",
        "required": [
          "type",
          "coordinates"
        ],
        "properties": {
          "type": {
            "const": "Polygon"
          },
          "coordinates": {
            "$ref": "#/components/schemas/GoogleMapsWorkerPolygonCoordinates"
          }
        }
      },
      "GoogleMapsWorkerPolygonCoordinates": {
        "type": "array",
        "minItems": 1,
        "items": {
          "$ref": "#/components/schemas/GoogleMapsWorkerLinearRing"
        }
      },
      "GoogleMapsWorkerPosition": {
        "type": "array",
        "minItems": 2,
        "maxItems": 2,
        "prefixItems": [
          {
            "type": "number",
            "minimum": -180,
            "maximum": 180
          },
          {
            "type": "number",
            "minimum": -90,
            "maximum": 90
          }
        ],
        "items": false
      },
      "GoogleMapsWorkerRegionAttribution": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "provider",
          "url",
          "license",
          "license_url",
          "text"
        ],
        "properties": {
          "provider": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "license": {
            "type": "string"
          },
          "license_url": {
            "type": "string"
          },
          "text": {
            "type": "string"
          },
          "boundary_id": {
            "type": "string"
          },
          "upstream_boundary_id": {
            "type": "string"
          },
          "metadata_warning": {
            "type": [
              "string",
              "null"
            ]
          },
          "year_represented": {
            "type": "string"
          },
          "original_source": {
            "type": "string"
          },
          "original_license": {
            "type": "string"
          },
          "original_license_url": {
            "type": "string"
          },
          "source_url": {
            "type": "string"
          }
        }
      },
      "GoogleMapsWorkerRegionId": {
        "type": "string",
        "maxLength": 200,
        "pattern": "^(gbOpen:[A-Z]{3}(-ADM[0-5]-[A-Za-z0-9]+:[A-Za-z0-9_.-]{1,128})?|geonames:[1-9][0-9]{0,11})$",
        "description": "Opaque gbOpen region handle or stable GeoNames city ID. Subdivision IDs change when the upstream snapshot changes; old IDs are never silently remapped."
      },
      "GoogleMapsWorkerRegionLevel": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "level",
          "type_names",
          "local_type",
          "boundary_id",
          "year_represented"
        ],
        "properties": {
          "level": {
            "type": "integer",
            "minimum": 0,
            "maximum": 5
          },
          "type_names": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "local_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "boundary_id": {
            "type": "string"
          },
          "year_represented": {
            "type": "string"
          }
        }
      },
      "GoogleMapsWorkerRegionPreview": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "status",
          "geometry",
          "bbox",
          "simplified"
        ],
        "properties": {
          "status": {
            "enum": [
              "available",
              "not_loaded",
              "unavailable",
              "too_complex"
            ]
          },
          "geometry": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/GoogleMapsWorkerPolygon"
              },
              {
                "$ref": "#/components/schemas/GoogleMapsWorkerMultiPolygon"
              },
              {
                "type": "null"
              }
            ]
          },
          "bbox": {
            "type": [
              "array",
              "null"
            ],
            "minItems": 4,
            "maxItems": 4,
            "items": {
              "type": "number"
            }
          },
          "simplified": {
            "const": true
          }
        },
        "description": "At most 2,000 coordinates and 64 KiB. Holes/components are preserved; geometry is null when no topology-preserving preview fits."
      },
      "GoogleMapsWorkerRegionRecord": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "country_id",
          "country_code",
          "country_name",
          "level",
          "parent_id",
          "parent_status",
          "ancestors",
          "local_name",
          "native_names",
          "english_name",
          "english_name_source",
          "display_name",
          "label",
          "aliases",
          "type_name",
          "local_type",
          "source_layer"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "country",
              "administrative",
              "city"
            ]
          },
          "city": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCityEvidence"
          },
          "preview": {
            "$ref": "#/components/schemas/GoogleMapsWorkerRegionPreview"
          },
          "id": {
            "$ref": "#/components/schemas/GoogleMapsWorkerRegionId"
          },
          "country_id": {
            "$ref": "#/components/schemas/GoogleMapsWorkerRegionId"
          },
          "country_code": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          },
          "country_name": {
            "type": "string"
          },
          "level": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "maximum": 5,
            "description": "Null for city records. OSM administrative levels are source metadata, not geoBoundaries ADM levels; never manufacture a crosswalk."
          },
          "parent_id": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/GoogleMapsWorkerRegionId"
              },
              {
                "type": "null"
              }
            ]
          },
          "parent_status": {
            "type": "string",
            "enum": [
              "root",
              "source_country",
              "inferred_containment",
              "unavailable",
              "ambiguous"
            ],
            "description": "gbOpen supplies country membership, not a universal parent crosswalk. Deeper parents require unique full polygon containment. Missing/overlapping parents remain explicit."
          },
          "ancestors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GoogleMapsWorkerRegionId"
            }
          },
          "local_name": {
            "type": "string"
          },
          "native_names": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "english_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "english_name_source": {
            "type": [
              "string",
              "null"
            ]
          },
          "display_name": {
            "type": "string"
          },
          "label": {
            "type": "string",
            "description": "English name when reliably matched to Unicode CLDR, otherwise the preserved local name, qualified by its available parent chain and country. Duplicate labels include a stable ID."
          },
          "aliases": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "type_name": {
            "type": "string",
            "description": "English ISO subdivision type where reliably matched, otherwise Administrative area (level N). Does not guess a translation of the source canonical type."
          },
          "local_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "source_layer": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/GoogleMapsWorkerRegionAttribution"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "GoogleMapsWorkerRegionSelection": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "administrative",
              "city"
            ]
          },
          "id": {
            "$ref": "#/components/schemas/GoogleMapsWorkerRegionId"
          },
          "country": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "pattern": "\\S"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "pattern": "\\S",
            "description": "Exact English/local name or alias; search first for substring matching."
          },
          "level": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5
          },
          "parent_id": {
            "$ref": "#/components/schemas/GoogleMapsWorkerRegionId"
          }
        },
        "oneOf": [
          {
            "required": [
              "id"
            ],
            "not": {
              "anyOf": [
                {
                  "required": [
                    "country"
                  ]
                },
                {
                  "required": [
                    "name"
                  ]
                },
                {
                  "required": [
                    "level"
                  ]
                },
                {
                  "required": [
                    "parent_id"
                  ]
                }
              ]
            }
          },
          {
            "required": [
              "country",
              "name",
              "level"
            ],
            "properties": {
              "kind": {
                "const": "administrative"
              }
            },
            "not": {
              "required": [
                "id"
              ]
            }
          },
          {
            "required": [
              "country",
              "name",
              "kind"
            ],
            "properties": {
              "kind": {
                "const": "city"
              }
            },
            "not": {
              "anyOf": [
                {
                  "required": [
                    "id"
                  ]
                },
                {
                  "required": [
                    "level"
                  ]
                },
                {
                  "required": [
                    "parent_id"
                  ]
                }
              ]
            }
          }
        ]
      },
      "GoogleMapsWorkerReviews": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "amount": {
            "type": [
              "number",
              "null"
            ],
            "default": null,
            "description": "Keep the source float-compatible type; do not change it to an integer."
          },
          "average": {
            "type": [
              "number",
              "null"
            ],
            "default": null
          }
        },
        "default": {
          "amount": null,
          "average": null
        }
      },
      "GoogleMapsWorkerScrapeRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "query",
          "region"
        ],
        "properties": {
          "query": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "pattern": "\\S",
            "description": "Search phrase, passed to the existing query encoder without rewriting."
          },
          "region": {
            "oneOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 128,
                "pattern": "\\S",
                "description": "Existing whole-country name/alias or ISO code. Bare French department codes are replaced by structured worldwide selection. Custom GeoJSON behavior is preserved."
              },
              {
                "$ref": "#/components/schemas/GoogleMapsWorkerRegionSelection"
              }
            ],
            "description": "A whole-country string or a structured named subdivision/stable ID from discovery. Ambiguous names fail with useful matches."
          },
          "geodata": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCustomGeodata"
          },
          "cache": {
            "$ref": "#/components/schemas/GoogleMapsWorkerCacheOptions"
          }
        },
        "allOf": [
          {
            "if": {
              "properties": {
                "region": {
                  "type": "object"
                }
              }
            },
            "then": {
              "not": {
                "required": [
                  "geodata"
                ]
              }
            }
          }
        ]
      },
      "GoogleMapsWorkerSeedCollection": {
        "type": "object",
        "required": [
          "type",
          "features"
        ],
        "properties": {
          "type": {
            "const": "FeatureCollection"
          },
          "features": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "type",
                "geometry"
              ],
              "properties": {
                "type": {
                  "const": "Feature"
                },
                "properties": {
                  "type": [
                    "object",
                    "null"
                  ]
                },
                "geometry": {
                  "type": "object",
                  "required": [
                    "type",
                    "coordinates"
                  ],
                  "properties": {
                    "type": {
                      "const": "Point"
                    },
                    "coordinates": {
                      "$ref": "#/components/schemas/GoogleMapsWorkerPosition"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "parameters": {
      "PageLimit": {
        "name": "limit",
        "in": "query",
        "description": "Maximum items per page. Use the returned next_cursor until it is null.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 50
        }
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "description": "Opaque cursor returned by this endpoint. Bound to the caller and filters; do not parse it or reuse it with changed filters. Malformed or mismatched cursors return 400 invalid_cursor.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 2048
        }
      }
    },
    "headers": {
      "RequestId": {
        "description": "Gateway-generated support correlation ID. Not a credential.",
        "schema": {
          "type": "string"
        }
      },
      "NoStore": {
        "description": "Account and job data must not be cached by browsers, proxies or CDNs.",
        "schema": {
          "type": "string",
          "const": "no-store"
        }
      },
      "RetryAfter": {
        "description": "Suggested whole seconds before the next eligible request. Does not authorize redispatch of an uncertain job.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "RateLimitPolicy": {
        "description": "Applicable timed quota policies: named entries with q=allowance, w=window seconds and qu=unit. Uses the May 2026 IETF draft format, not an RFC guarantee.",
        "schema": {
          "type": "string"
        },
        "example": "\"requests\";q=120;w=60;qu=\"requests\""
      },
      "RateLimit": {
        "description": "Snapshots after this request: named entries with r=remaining units and t=seconds until reset/full refill. REST and MCP share user budgets. Snapshots do not reserve future capacity.",
        "schema": {
          "type": "string"
        },
        "example": "\"requests\";r=119;t=37"
      },
      "Limits": {
        "description": "JSON array of applicable limits. Each item contains name, limit, remaining, scope, unit, cost, window_seconds, reset_at (Unix UTC seconds) and reset_after (seconds). Concurrency entries have null window/reset fields because capacity returns when jobs/transfers finish. cost is the required allowance for this action, not necessarily charged on rejection. Download byte cost is null until the requested file size is known. Polling/events do not charge execution quotas. On /me, connection limits for other actions are also included.",
        "schema": {
          "type": "string"
        },
        "example": "[{\"name\":\"requests\",\"limit\":120,\"remaining\":119,\"window_seconds\":60,\"reset_at\":1792500060,\"reset_after\":37,\"scope\":\"user\",\"unit\":\"requests\",\"cost\":1}]"
      },
      "LimitsStatus": {
        "description": "Present as unavailable if the quota snapshot database read failed. Known ingress limits remain available; missing user counters must not be interpreted as unlimited.",
        "schema": {
          "type": "string"
        },
        "example": "unavailable"
      }
    }
  },
  "x-gtmfree-status": "deployed",
  "x-gtmfree-mcp": {
    "endpoint": "https://gtmfree.com/mcp",
    "authentication": "Validate WorkOS OAuth issuer, audience, expiry and scopes, then map to the same local user. No shared master key.",
    "exposure": "Allowlist listTools, createGoogleMapsJob, listJobs, getJob, getJobResults and getJobExport. Results use a byte-bounded paginated projection; exports use binary-safe base64 chunks up to 128 KiB of raw bytes. Account actions and REST SSE are excluded.",
    "job_policy": "Use the same job service as REST for ownership, quotas and atomic per-user/tool admission. Each accepted submission creates a new job.",
    "events": "Stateless Streamable HTTP with JSON responses; poll getJob. MCP tasks and server-initiated event streams are not advertised.",
    "limits": "HTTP responses include RateLimit-Policy, RateLimit and GTMFree-Limits. JSON-RPC results also include result._meta[\"gtmfree/limits\"]; protocol errors use error.data[\"gtmfree/limits\"]. Tool errors keep the same metadata and expose Retry-After on HTTP plus error.retry_after in structuredContent.",
    "exports": "getJobExport accepts job_id, format, optional offset and maximum_bytes (default 65536, maximum 131072). Decode content_base64 and concatenate chunks in order; next_offset=null ends the file. Only requested, retained exports are accessible. Charge admitted raw chunk bytes to the same REST download allowance; repeated chunks are charged again.",
    "projections": {
      "getJobResults": {
        "source_operation": "getJobResults",
        "maximum_record_bytes_per_page": 122880
      },
      "getJobExport": {
        "source_operation": "downloadJobFile",
        "maximum_chunk_bytes": 131072,
        "default_chunk_bytes": 65536,
        "description": "Binary-safe chunks of requested exports. Each chunk also includes region provenance when available; preserve its original source/license notices."
      }
    }
  },
  "x-gtmfree-worker-contract": {
    "service": "google-maps-scraper",
    "source_file": "openapi.json",
    "source_version": "0.7.0",
    "source_sha256": "8f21ffcaecfe0db45fddedd5a43195e46cabc55faabcf8810b0f9a04fa5594cb"
  },
  "x-gtmfree-contract-rules": {
    "authentication": "Bearer API key for REST; website sessions and MCP OAuth resolve to the same enrolled local user but are not interchangeable credentials.",
    "ownership": "Resolve owner before all job/result/file reads and before any worker operation. Missing and foreign jobs share the same 404 response.",
    "terminal_statuses": [
      "succeeded",
      "failed"
    ],
    "active_statuses": [
      "submitting",
      "submission_unknown",
      "queued",
      "running"
    ],
    "maximum_active_jobs_per_user_per_tool": 1,
    "pagination": {
      "default_limit": 50,
      "maximum_limit": 100,
      "cursor_scope": [
        "user_id",
        "endpoint",
        "filters",
        "result_revision_if_applicable"
      ]
    },
    "results": "Freeze retained results per job. REST exposes typed pages and binary export responses. MCP exposes smaller typed pages and bounded, base64-encoded export chunks. Never expose raw worker snapshots or private cache namespaces.",
    "network": "Apply jurisdiction and Spamhaus checks everywhere, including catalog and documentation. Only new local enrollment uses hosting detection.",
    "implementation_status": "REST/auth/account, shared job policy, reviewed OpenAPI HTTP serving, self-hosted Scalar, caller-aware FastMCP/WorkOS OAuth and generated Python/TypeScript SDKs implemented. SDK CI validates generation drift, builds packages and smoke-tests clients. WebMCP, registry publishing and separate SDK-repository synchronization remain separate work."
  },
  "x-gtmfree-abuse-policy": {
    "source": "config/abuse-policy.json",
    "defaults": {
      "version": 1,
      "ingress": {
        "requests_per_second": 100,
        "burst": 200,
        "ip_requests_per_second": 10,
        "ip_burst": 40,
        "maximum_ip_buckets": 4096,
        "maximum_inflight": 64,
        "maximum_header_bytes": 16384,
        "maximum_body_bytes": 262144,
        "body_timeout_seconds": 10,
        "send_timeout_seconds": 15
      },
      "api": {
        "requests_per_minute": 120,
        "submission_attempts_per_minute": 10,
        "daily_jobs": 20,
        "daily_point_units": 100000,
        "daily_worker_seconds": 7200,
        "downloads_bytes_per_hour": 4294967296,
        "profile_cache_seconds": 30,
        "maximum_profile_cache_entries": 256,
        "maximum_profile_calls": 4
      },
      "jobs": {
        "maximum_active": 8,
        "maximum_records": 100000,
        "maximum_result_bytes": 1073741824,
        "maximum_retained_bytes": 17179869184,
        "maximum_retained_jobs": 1000,
        "result_retention_seconds": 604800,
        "metadata_retention_seconds": 2592000,
        "maximum_public_response_bytes": 1048576,
        "minimum_free_disk_bytes": 1073741824,
        "pause_file": ".data/pause-submissions"
      },
      "maps": {
        "maximum_geodata_positions": 5000,
        "reserved_points_per_job": 50000,
        "reserved_worker_seconds_per_job": 3600
      },
      "rpc": {
        "maximum_connections": 2,
        "maximum_frame_bytes": 1048576,
        "timeout_seconds": 10,
        "observation_interval_seconds": 2
      },
      "streams": {
        "maximum_global": 32,
        "maximum_per_user": 6,
        "maximum_per_job": 2,
        "heartbeat_seconds": 15,
        "reauthorize_seconds": 30,
        "maximum_lifetime_seconds": 900
      },
      "mcp": {
        "maximum_global": 32,
        "maximum_per_user": 6,
        "maximum_request_seconds": 30
      },
      "downloads": {
        "maximum_global": 4,
        "maximum_per_user": 2,
        "maximum_lifetime_seconds": 900
      },
      "regions": {
        "requests_per_minute": 30,
        "loads_per_day": 6,
        "maximum_global": 1,
        "maximum_per_user": 1,
        "wait_seconds": 5,
        "worker_timeout_seconds": 1800
      }
    },
    "accounting": "Limits belong to the local user across API keys. Daily work reserves worst-case points/runtime at admission; known unused work is refunded once at terminal observation. Unknown outcomes retain reservations. UTC-day windows; download bytes use UTC-hour windows and charge the full file before streaming, including interrupted downloads. MCP export chunks share the download budget and leases, charging only the admitted raw chunk bytes before delivery.",
    "deployment": "NGINX, Cloudflare and worker settings must be installed separately; gateway limits apply locally. Values are configurable operator limits, not a service guarantee."
  },
  "x-gtmfree-rate-limits": {
    "snapshot": "Response headers are admission snapshots, not reservations. User budgets are shared across all REST keys and MCP clients. Fixed windows reset on Unix-aligned minute/hour/UTC-day boundaries. Token buckets refill continuously; reset means full refill. Concurrency has no scheduled reset.",
    "costs": "New Maps work reserves 1 daily job, 50000 points and 3600 worker seconds. Reservations are settled when work completes; small/cache-hit jobs release unused work capacity. Requests can be rejected even with daily jobs remaining if another required budget is insufficient.",
    "streams": "Events charge one authenticated request per connection, not per heartbeat or status event. Headers describe the connection-opening snapshot. Streams close after 900 seconds; downloads after 120 seconds. MCP requests last at most 30 seconds.",
    "edge": "Cloudflare Free and NGINX can reject before the application, with non-JSON responses and without user quota counters. NGINX rejections include Retry-After and GTMFree-Limits-Status=edge. No global capacity or edge availability is guaranteed by a positive remaining value."
  }
}
