{
    "openapi": "3.0.3",
    "info": {
        "title": "RFPPlanet Data API",
        "version": "1.0.0",
        "description": "RFPs, bids and tenders from government agencies and private-sector buyers in the United States and Canada, including US federal opportunities, as JSON.\n\n**Authentication:** send your key in the `Authorization: Bearer <key>` header.\n\n**Usage:** metered by records returned. Every response carries `X-Records-Remaining` and `X-RateLimit-Remaining` headers.\n\n**Pagination:** cursor based. Pass `meta.next_cursor` back as `cursor` until `has_more` is false.\n\n**Sync:** call `/rfps?status=all&sort=updated_asc&updated_since=<last run>` to fetch only changes, or let us push them to you with **webhooks** (see below).\n\nGet a key at https://rfpplanet.com/api-access.",
        "contact": {
            "name": "RFPPlanet",
            "url": "https://rfpplanet.com/api-access#contact"
        }
    },
    "servers": [
        {
            "url": "https://rfpplanet.com/api/v1"
        }
    ],
    "security": [
        {
            "bearerAuth": []
        }
    ],
    "tags": [
        {
            "name": "RFPs",
            "description": "State, provincial and local opportunities."
        },
        {
            "name": "Federal",
            "description": "US federal opportunities (SAM.gov). Plans with federal access."
        },
        {
            "name": "Reference",
            "description": "Lists for filters. Free."
        },
        {
            "name": "Account",
            "description": "Your usage. Free."
        },
        {
            "name": "Exports",
            "description": "Daily bulk files of every active RFP and federal notice. Plans with bulk export (Enterprise)."
        },
        {
            "name": "Webhooks",
            "description": "Plans with webhooks (Pro and above) can have new and changed RFPs **pushed** to an https endpoint instead of polling. Add endpoints, choose events and filters, send a test event and see recent deliveries on the **Developer** page of your account (https://rfpplanet.com/developer).\n\n**Delivery:** a `POST` with a JSON body; each event is one RFP. We check for changes every few minutes. Reply with any `2xx` within 10 seconds; otherwise we retry after 1 min, 5 min, 30 min, 2 h, 6 h and 12 h, then mark it failed (you can retry it from the Developer page). After 50 failures in a row with no success for a day, the webhook is paused and we email you. Each event counts as one record of your monthly quota.\n\n**Order and duplicates:** process events idempotently by `data.id` (upsert) and ignore a repeated `X-RFPPlanet-Delivery` id.\n\n| Header | Meaning |\n|---|---|\n| `X-RFPPlanet-Event` | Event name, e.g. rfp.created |\n| `X-RFPPlanet-Delivery` | Unique delivery id (dlv_…); the same id is reused on retries, so use it to ignore duplicates |\n| `X-RFPPlanet-Timestamp` | Unix time the request was signed |\n| `X-RFPPlanet-Signature` | v1=<hex HMAC-SHA256 of \"{timestamp}.{raw body}\" with your signing secret> |\n\n**Verify the signature** before trusting a delivery: compute HMAC-SHA256 of `{timestamp}.{raw body}` with your signing secret and compare it to the `v1=` value in constant time. Reject timestamps older than 5 minutes.\n\n**Node.js**\n\n```javascript\n// Express: keep the raw body, it is what we signed\napp.post('/hooks/rfpplanet', express.raw({ type: 'application/json' }), (req, res) => {\n  const crypto = require('crypto');\n  const ts = req.get('X-RFPPlanet-Timestamp');\n  const sig = (req.get('X-RFPPlanet-Signature') || '').replace('v1=', '');\n  const expected = crypto.createHmac('sha256', process.env.RFPPLANET_WEBHOOK_SECRET)\n    .update(`${ts}.${req.body}`).digest('hex');\n  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;\n  if (!fresh || sig.length !== expected.length ||\n      !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {\n    return res.sendStatus(401);\n  }\n  const event = JSON.parse(req.body);\n  // upsert event.data by event.data.id, then answer quickly:\n  res.sendStatus(200);\n});\n```\n\n**Python**\n\n```python\n# Flask\nimport hmac, hashlib, os, time\nfrom flask import Flask, request, abort\n\napp = Flask(__name__)\nSECRET = os.environ[\"RFPPLANET_WEBHOOK_SECRET\"].encode()\n\n@app.post(\"/hooks/rfpplanet\")\ndef rfpplanet_hook():\n    ts = request.headers.get(\"X-RFPPlanet-Timestamp\", \"0\")\n    sig = request.headers.get(\"X-RFPPlanet-Signature\", \"\").removeprefix(\"v1=\")\n    body = request.get_data()  # raw bytes\n    expected = hmac.new(SECRET, ts.encode() + b\".\" + body, hashlib.sha256).hexdigest()\n    if abs(time.time() - int(ts)) > 300 or not hmac.compare_digest(sig, expected):\n        abort(401)\n    event = request.get_json()\n    # upsert event[\"data\"] by event[\"data\"][\"id\"]\n    return \"\", 200\n```\n\n**PHP**\n\n```php\n<?php\n$body = file_get_contents('php://input');            // raw body\n$ts   = $_SERVER['HTTP_X_RFPPLANET_TIMESTAMP'] ?? '0';\n$sig  = substr($_SERVER['HTTP_X_RFPPLANET_SIGNATURE'] ?? '', 3); // drop \"v1=\"\n$expected = hash_hmac('sha256', $ts . '.' . $body, getenv('RFPPLANET_WEBHOOK_SECRET'));\n\nif (abs(time() - (int) $ts) > 300 || !hash_equals($expected, $sig)) {\n    http_response_code(401);\n    exit;\n}\n$event = json_decode($body, true);\n// upsert $event['data'] by $event['data']['id']\nhttp_response_code(200);\n```\n\n**No-code:** paste a Zapier \"Catch Hook\" or Make \"Custom webhook\" URL as the endpoint to send RFPs to Salesforce, HubSpot, Sheets, Slack and more."
        }
    ],
    "paths": {
        "/rfps": {
            "get": {
                "tags": [
                    "RFPs"
                ],
                "summary": "Search and list RFPs",
                "description": "Uses one record per RFP returned.",
                "operationId": "listRfps",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "description": "Keyword in title, organization, RFP number or scope of work.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "description": "open (default), closed, cancelled, awarded, all.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "open",
                                "closed",
                                "cancelled",
                                "awarded",
                                "all"
                            ]
                        }
                    },
                    {
                        "name": "category",
                        "in": "query",
                        "required": false,
                        "description": "Category ids or slugs, comma separated (see /categories).",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "country",
                        "in": "query",
                        "required": false,
                        "description": "Country ISO code, id or name, comma separated (US, CA).",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "region",
                        "in": "query",
                        "required": false,
                        "description": "State / province ids or slugs, comma separated (see /regions).",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "notice_type",
                        "in": "query",
                        "required": false,
                        "description": "Text match on notice type (e.g. RFQ).",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "posted_from",
                        "in": "query",
                        "required": false,
                        "description": "Posted on or after (YYYY-MM-DD).",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "posted_to",
                        "in": "query",
                        "required": false,
                        "description": "Posted on or before (YYYY-MM-DD).",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "deadline_from",
                        "in": "query",
                        "required": false,
                        "description": "Deadline on or after (YYYY-MM-DD).",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "deadline_to",
                        "in": "query",
                        "required": false,
                        "description": "Deadline on or before (YYYY-MM-DD).",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "updated_since",
                        "in": "query",
                        "required": false,
                        "description": "Only rows changed since this time: ISO 8601 or Unix seconds/milliseconds. Use for incremental sync.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "required": false,
                        "description": "posted_desc (default), posted_asc, updated_asc, deadline_asc.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "posted_desc",
                                "posted_asc",
                                "updated_asc",
                                "deadline_asc"
                            ]
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "required": false,
                        "description": "Results per page, 1–100 (default 25).",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "cursor",
                        "in": "query",
                        "required": false,
                        "description": "Value of meta.next_cursor from the previous page.",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Rfp"
                                            }
                                        },
                                        "meta": {
                                            "type": "object",
                                            "properties": {
                                                "count": {
                                                    "type": "integer"
                                                },
                                                "limit": {
                                                    "type": "integer"
                                                },
                                                "has_more": {
                                                    "type": "boolean"
                                                },
                                                "next_cursor": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "records_remaining": {
                                                    "type": "integer"
                                                }
                                            }
                                        },
                                        "links": {
                                            "type": "object",
                                            "properties": {
                                                "next": {
                                                    "type": "string",
                                                    "nullable": true
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/Error"
                    },
                    "401": {
                        "$ref": "#/components/responses/Error"
                    },
                    "403": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    }
                }
            }
        },
        "/rfps/{id}": {
            "get": {
                "tags": [
                    "RFPs"
                ],
                "summary": "Get one RFP",
                "operationId": "getRfp",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "example": "SYS-6837"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Rfp"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/Error"
                    },
                    "401": {
                        "$ref": "#/components/responses/Error"
                    },
                    "403": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    }
                }
            }
        },
        "/rfps/{id}/documents": {
            "get": {
                "tags": [
                    "RFPs"
                ],
                "summary": "RFP documents",
                "description": "Signed download links valid for 15 minutes. One record per file. Plans with documents only.",
                "operationId": "getRfpDocuments",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "example": "SYS-6837"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Document"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/Error"
                    },
                    "401": {
                        "$ref": "#/components/responses/Error"
                    },
                    "403": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    }
                }
            }
        },
        "/federal": {
            "get": {
                "tags": [
                    "Federal"
                ],
                "summary": "Search and list federal opportunities",
                "operationId": "listFederal",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "description": "Keyword in title, description, solicitation number or agency.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "description": "open (default), closed, all.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "open",
                                "closed",
                                "all"
                            ]
                        }
                    },
                    {
                        "name": "category",
                        "in": "query",
                        "required": false,
                        "description": "Category ids or slugs, comma separated (see /categories).",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "naics",
                        "in": "query",
                        "required": false,
                        "description": "NAICS codes or prefixes, comma separated (e.g. 5415,56171).",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "notice_type",
                        "in": "query",
                        "required": false,
                        "description": "Text match on notice type (e.g. RFQ).",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "posted_from",
                        "in": "query",
                        "required": false,
                        "description": "Posted on or after (YYYY-MM-DD).",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "posted_to",
                        "in": "query",
                        "required": false,
                        "description": "Posted on or before (YYYY-MM-DD).",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "deadline_from",
                        "in": "query",
                        "required": false,
                        "description": "Deadline on or after (YYYY-MM-DD).",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "deadline_to",
                        "in": "query",
                        "required": false,
                        "description": "Deadline on or before (YYYY-MM-DD).",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "updated_since",
                        "in": "query",
                        "required": false,
                        "description": "Only rows changed since this time: ISO 8601 or Unix seconds/milliseconds. Use for incremental sync.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "required": false,
                        "description": "posted_desc (default), posted_asc, updated_asc, deadline_asc.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "posted_desc",
                                "posted_asc",
                                "updated_asc",
                                "deadline_asc"
                            ]
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "required": false,
                        "description": "Results per page, 1–100 (default 25).",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "cursor",
                        "in": "query",
                        "required": false,
                        "description": "Value of meta.next_cursor from the previous page.",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/FederalOpportunity"
                                            }
                                        },
                                        "meta": {
                                            "type": "object",
                                            "properties": {
                                                "count": {
                                                    "type": "integer"
                                                },
                                                "limit": {
                                                    "type": "integer"
                                                },
                                                "has_more": {
                                                    "type": "boolean"
                                                },
                                                "next_cursor": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "records_remaining": {
                                                    "type": "integer"
                                                }
                                            }
                                        },
                                        "links": {
                                            "type": "object",
                                            "properties": {
                                                "next": {
                                                    "type": "string",
                                                    "nullable": true
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/Error"
                    },
                    "401": {
                        "$ref": "#/components/responses/Error"
                    },
                    "403": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    }
                }
            }
        },
        "/federal/{id}": {
            "get": {
                "tags": [
                    "Federal"
                ],
                "summary": "Get one federal opportunity",
                "description": "Accepts the RFPPlanet id (FED-…) or the SAM.gov notice id.",
                "operationId": "getFederal",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "example": "FED-03681"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/FederalOpportunity"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/Error"
                    },
                    "401": {
                        "$ref": "#/components/responses/Error"
                    },
                    "403": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    }
                }
            }
        },
        "/categories": {
            "get": {
                "tags": [
                    "Reference"
                ],
                "summary": "Categories",
                "operationId": "listCategories",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "type": "object",
                                                "properties": {
                                                    "id": {
                                                        "type": "integer"
                                                    },
                                                    "name": {
                                                        "type": "string"
                                                    },
                                                    "slug": {
                                                        "type": "string"
                                                    },
                                                    "federal": {
                                                        "type": "boolean"
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Error"
                    },
                    "403": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    }
                }
            }
        },
        "/regions": {
            "get": {
                "tags": [
                    "Reference"
                ],
                "summary": "States and provinces",
                "operationId": "listRegions",
                "parameters": [
                    {
                        "name": "country",
                        "in": "query",
                        "schema": {
                            "type": "string"
                        },
                        "example": "US"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "type": "object",
                                                "properties": {
                                                    "id": {
                                                        "type": "integer"
                                                    },
                                                    "name": {
                                                        "type": "string"
                                                    },
                                                    "slug": {
                                                        "type": "string"
                                                    },
                                                    "country": {
                                                        "type": "object"
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Error"
                    },
                    "403": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    }
                }
            }
        },
        "/countries": {
            "get": {
                "tags": [
                    "Reference"
                ],
                "summary": "Countries",
                "operationId": "listCountries",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "type": "object",
                                                "properties": {
                                                    "id": {
                                                        "type": "integer"
                                                    },
                                                    "name": {
                                                        "type": "string"
                                                    },
                                                    "code": {
                                                        "type": "string"
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Error"
                    },
                    "403": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    }
                }
            }
        },
        "/notice-types": {
            "get": {
                "tags": [
                    "Reference"
                ],
                "summary": "Notice types",
                "operationId": "listNoticeTypes",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "type": "string"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Error"
                    },
                    "403": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    }
                }
            }
        },
        "/usage": {
            "get": {
                "tags": [
                    "Account"
                ],
                "summary": "Your usage this month",
                "operationId": "getUsage",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "plan": {
                                                    "type": "string"
                                                },
                                                "period_start": {
                                                    "type": "string",
                                                    "format": "date"
                                                },
                                                "period_end": {
                                                    "type": "string",
                                                    "format": "date"
                                                },
                                                "records_limit": {
                                                    "type": "integer"
                                                },
                                                "records_used": {
                                                    "type": "integer"
                                                },
                                                "records_remaining": {
                                                    "type": "integer"
                                                },
                                                "requests_per_minute": {
                                                    "type": "integer"
                                                },
                                                "features": {
                                                    "type": "object"
                                                },
                                                "access_expires_at": {
                                                    "type": "string",
                                                    "nullable": true
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Error"
                    },
                    "403": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    }
                }
            }
        },
        "/exports": {
            "get": {
                "tags": [
                    "Exports"
                ],
                "summary": "List bulk export files",
                "description": "Files are rebuilt daily and kept for 7 days. Each has a signed `download_url` valid for 60 minutes. Exports do not use the record quota.",
                "operationId": "listExports",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/ExportFile"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Error"
                    },
                    "403": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    }
                }
            }
        }
    },
    "x-webhooks": {
        "rfp.created": {
            "post": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "rfp.created",
                "description": "A new RFP matching your filters was published.",
                "operationId": "webhook_rfp_created",
                "parameters": [
                    {
                        "name": "X-RFPPlanet-Event",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Event name, e.g. rfp.created"
                    },
                    {
                        "name": "X-RFPPlanet-Delivery",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Unique delivery id (dlv_…); the same id is reused on retries, so use it to ignore duplicates"
                    },
                    {
                        "name": "X-RFPPlanet-Timestamp",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Unix time the request was signed"
                    },
                    {
                        "name": "X-RFPPlanet-Signature",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "v1=<hex HMAC-SHA256 of \"{timestamp}.{raw body}\" with your signing secret>"
                    }
                ],
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "id": {
                                        "type": "string",
                                        "example": "dlv_10452"
                                    },
                                    "event": {
                                        "type": "string",
                                        "example": "rfp.created"
                                    },
                                    "created_at": {
                                        "type": "string",
                                        "format": "date-time"
                                    },
                                    "api_version": {
                                        "type": "string",
                                        "example": "v1"
                                    },
                                    "data": {
                                        "$ref": "#/components/schemas/Rfp"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Any 2xx within 10 seconds marks the delivery as done. Anything else is retried."
                    }
                }
            }
        },
        "rfp.updated": {
            "post": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "rfp.updated",
                "description": "An RFP you could already see changed: deadline extended, addendum issued, cancelled, awarded or details corrected.",
                "operationId": "webhook_rfp_updated",
                "parameters": [
                    {
                        "name": "X-RFPPlanet-Event",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Event name, e.g. rfp.created"
                    },
                    {
                        "name": "X-RFPPlanet-Delivery",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Unique delivery id (dlv_…); the same id is reused on retries, so use it to ignore duplicates"
                    },
                    {
                        "name": "X-RFPPlanet-Timestamp",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Unix time the request was signed"
                    },
                    {
                        "name": "X-RFPPlanet-Signature",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "v1=<hex HMAC-SHA256 of \"{timestamp}.{raw body}\" with your signing secret>"
                    }
                ],
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "id": {
                                        "type": "string",
                                        "example": "dlv_10452"
                                    },
                                    "event": {
                                        "type": "string",
                                        "example": "rfp.updated"
                                    },
                                    "created_at": {
                                        "type": "string",
                                        "format": "date-time"
                                    },
                                    "api_version": {
                                        "type": "string",
                                        "example": "v1"
                                    },
                                    "data": {
                                        "$ref": "#/components/schemas/Rfp"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Any 2xx within 10 seconds marks the delivery as done. Anything else is retried."
                    }
                }
            }
        },
        "federal.created": {
            "post": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "federal.created",
                "description": "A new US federal notice (plans with federal access).",
                "operationId": "webhook_federal_created",
                "parameters": [
                    {
                        "name": "X-RFPPlanet-Event",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Event name, e.g. rfp.created"
                    },
                    {
                        "name": "X-RFPPlanet-Delivery",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Unique delivery id (dlv_…); the same id is reused on retries, so use it to ignore duplicates"
                    },
                    {
                        "name": "X-RFPPlanet-Timestamp",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Unix time the request was signed"
                    },
                    {
                        "name": "X-RFPPlanet-Signature",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "v1=<hex HMAC-SHA256 of \"{timestamp}.{raw body}\" with your signing secret>"
                    }
                ],
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "id": {
                                        "type": "string",
                                        "example": "dlv_10452"
                                    },
                                    "event": {
                                        "type": "string",
                                        "example": "federal.created"
                                    },
                                    "created_at": {
                                        "type": "string",
                                        "format": "date-time"
                                    },
                                    "api_version": {
                                        "type": "string",
                                        "example": "v1"
                                    },
                                    "data": {
                                        "$ref": "#/components/schemas/FederalOpportunity"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Any 2xx within 10 seconds marks the delivery as done. Anything else is retried."
                    }
                }
            }
        },
        "federal.updated": {
            "post": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "federal.updated",
                "description": "A US federal notice changed.",
                "operationId": "webhook_federal_updated",
                "parameters": [
                    {
                        "name": "X-RFPPlanet-Event",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Event name, e.g. rfp.created"
                    },
                    {
                        "name": "X-RFPPlanet-Delivery",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Unique delivery id (dlv_…); the same id is reused on retries, so use it to ignore duplicates"
                    },
                    {
                        "name": "X-RFPPlanet-Timestamp",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Unix time the request was signed"
                    },
                    {
                        "name": "X-RFPPlanet-Signature",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "v1=<hex HMAC-SHA256 of \"{timestamp}.{raw body}\" with your signing secret>"
                    }
                ],
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "id": {
                                        "type": "string",
                                        "example": "dlv_10452"
                                    },
                                    "event": {
                                        "type": "string",
                                        "example": "federal.updated"
                                    },
                                    "created_at": {
                                        "type": "string",
                                        "format": "date-time"
                                    },
                                    "api_version": {
                                        "type": "string",
                                        "example": "v1"
                                    },
                                    "data": {
                                        "$ref": "#/components/schemas/FederalOpportunity"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Any 2xx within 10 seconds marks the delivery as done. Anything else is retried."
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "bearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "description": "Your RFPPlanet API key."
            }
        },
        "schemas": {
            "Rfp": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "RFPPlanet RFP number. Use it with /rfps/{id}.",
                        "example": "SYS-6837"
                    },
                    "title": {
                        "type": "string",
                        "description": "Title of the opportunity.",
                        "example": "Electronic Document and Records Management System"
                    },
                    "organization": {
                        "type": "string",
                        "description": "Issuing organization or agency.",
                        "nullable": true,
                        "example": "City of Fredericton"
                    },
                    "notice_type": {
                        "type": "string",
                        "description": "RFP, RFQ, RFI, IFB, Sources Sought, etc.",
                        "nullable": true,
                        "example": "RFP (Request for Proposal)"
                    },
                    "status": {
                        "type": "string",
                        "description": "open, closed, cancelled or awarded.",
                        "example": "open"
                    },
                    "countries": {
                        "type": "array",
                        "items": {
                            "type": "object"
                        },
                        "description": "Countries: [{id, name, code}] where code is ISO 3166 (US, CA)."
                    },
                    "regions": {
                        "type": "array",
                        "items": {
                            "type": "object"
                        },
                        "description": "States / provinces: [{id, name, slug}]."
                    },
                    "category": {
                        "type": "object",
                        "description": "Main category {id, name, slug}.",
                        "nullable": true
                    },
                    "categories": {
                        "type": "array",
                        "items": {
                            "type": "object"
                        },
                        "description": "All categories, main category first."
                    },
                    "posted_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When the RFP was published on RFPPlanet (ISO 8601).",
                        "example": "2026-10-01T16:06:10-04:00"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "Last change. Use with updated_since for sync.",
                        "example": "2026-10-01T16:10:14-04:00"
                    },
                    "deadline": {
                        "type": "string",
                        "format": "date",
                        "description": "Proposal due date (YYYY-MM-DD).",
                        "nullable": true,
                        "example": "2026-10-19"
                    },
                    "questions_deadline": {
                        "type": "string",
                        "format": "date",
                        "description": "Last day to submit questions.",
                        "nullable": true,
                        "example": "2026-10-05"
                    },
                    "pre_bid_meeting": {
                        "type": "string",
                        "format": "date",
                        "description": "Pre-bid / site meeting date.",
                        "nullable": true
                    },
                    "contract_term": {
                        "type": "string",
                        "description": "Contract length as published.",
                        "nullable": true,
                        "example": "7 Years"
                    },
                    "work_location": {
                        "type": "string",
                        "description": "Onsite, Offsite or Hybrid.",
                        "nullable": true,
                        "example": "Offsite"
                    },
                    "submission_method": {
                        "type": "string",
                        "description": "How bids are submitted.",
                        "nullable": true,
                        "example": "Email"
                    },
                    "estimated_budget": {
                        "type": "number",
                        "description": "Estimated contract value in USD, when published.",
                        "nullable": true,
                        "example": 250000
                    },
                    "eligibility": {
                        "type": "string",
                        "description": "Who can bid (plain text).",
                        "nullable": true,
                        "example": "Canada Organization"
                    },
                    "description": {
                        "type": "string",
                        "description": "Scope of work as plain text.",
                        "nullable": true,
                        "example": "Electronic Document and Records Management System will deliver…"
                    },
                    "description_html": {
                        "type": "string",
                        "description": "Scope of work as HTML. Sanitize before displaying.",
                        "nullable": true,
                        "example": "<p>Electronic Document…</p>"
                    },
                    "flags": {
                        "type": "object",
                        "description": "date_extended, addendum_issued, cancelled, awarded (booleans)."
                    },
                    "documents_available": {
                        "type": "integer",
                        "description": "Number of files you can fetch from /rfps/{id}/documents.",
                        "example": 1
                    },
                    "source_url": {
                        "type": "string",
                        "description": "Original posting. Plans with source links only; otherwise null.",
                        "nullable": true,
                        "example": "https://nbon-rpanb.gnb.ca/…"
                    },
                    "url": {
                        "type": "string",
                        "description": "RFP page on RFPPlanet.",
                        "example": "https://rfpplanet.com/SYS-6837/electronic-document-and-records-management-system"
                    }
                }
            },
            "FederalOpportunity": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "RFPPlanet federal id. Use it with /federal/{id}.",
                        "example": "FED-03681"
                    },
                    "sam_notice_id": {
                        "type": "string",
                        "description": "SAM.gov notice id.",
                        "nullable": true,
                        "example": "14BFA783F26D4AA7B1F0CAA65CB249F3"
                    },
                    "solicitation_number": {
                        "type": "string",
                        "description": "Agency solicitation number.",
                        "nullable": true,
                        "example": "19NP4026Q0028"
                    },
                    "title": {
                        "type": "string",
                        "description": "Title.",
                        "example": "Pest Control Services for Embassy Properties"
                    },
                    "agency": {
                        "type": "string",
                        "description": "Contracting agency.",
                        "nullable": true,
                        "example": "Department of State"
                    },
                    "notice_type": {
                        "type": "string",
                        "description": "Solicitation, Presolicitation, Sources Sought, …",
                        "nullable": true,
                        "example": "Solicitation"
                    },
                    "status": {
                        "type": "string",
                        "description": "open or closed.",
                        "example": "open"
                    },
                    "naics_code": {
                        "type": "string",
                        "description": "NAICS code.",
                        "nullable": true,
                        "example": "56171"
                    },
                    "set_aside": {
                        "type": "string",
                        "description": "Small-business set-aside, if any.",
                        "nullable": true,
                        "example": "Total Small Business"
                    },
                    "category": {
                        "type": "object",
                        "description": "RFPPlanet category {id, name, slug}.",
                        "nullable": true
                    },
                    "office": {
                        "type": "object",
                        "description": "Contracting office {street, city, state, zip, country}.",
                        "nullable": true
                    },
                    "place_of_performance": {
                        "type": "object",
                        "description": "Where the work is done.",
                        "nullable": true
                    },
                    "posted_at": {
                        "type": "string",
                        "format": "date",
                        "description": "Publish date.",
                        "example": "2026-06-12"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "Last change on RFPPlanet.",
                        "example": "2026-06-12T06:11:23-04:00"
                    },
                    "deadline": {
                        "type": "string",
                        "format": "date",
                        "description": "Response due date.",
                        "nullable": true,
                        "example": "2026-06-25"
                    },
                    "description": {
                        "type": "string",
                        "description": "Description (plain text).",
                        "nullable": true,
                        "example": "Pest Control Services for US Embassy Nepal Properties"
                    },
                    "source_url": {
                        "type": "string",
                        "description": "SAM.gov link. Plans with source links only.",
                        "nullable": true,
                        "example": "https://sam.gov/…"
                    },
                    "url": {
                        "type": "string",
                        "description": "Page on RFPPlanet.",
                        "example": "https://rfpplanet.com/federal-rfps/FED-03681"
                    }
                }
            },
            "Document": {
                "type": "object",
                "properties": {
                    "name": {
                        "type": "string",
                        "example": "SYS-6837.zip"
                    },
                    "size_bytes": {
                        "type": "integer",
                        "nullable": true
                    },
                    "uploaded_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "download_url": {
                        "type": "string"
                    },
                    "expires_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "ExportFile": {
                "type": "object",
                "properties": {
                    "name": {
                        "type": "string",
                        "example": "rfps-full-2026-10-05.jsonl.gz"
                    },
                    "dataset": {
                        "type": "string",
                        "enum": [
                            "rfps",
                            "federal"
                        ]
                    },
                    "format": {
                        "type": "string",
                        "enum": [
                            "jsonl",
                            "csv"
                        ]
                    },
                    "date": {
                        "type": "string",
                        "format": "date"
                    },
                    "size_bytes": {
                        "type": "integer"
                    },
                    "records": {
                        "type": "integer",
                        "nullable": true
                    },
                    "download_url": {
                        "type": "string"
                    },
                    "expires_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "Error": {
                "type": "object",
                "properties": {
                    "error": {
                        "type": "object",
                        "properties": {
                            "code": {
                                "type": "string",
                                "enum": [
                                    "missing_api_key",
                                    "invalid_api_key",
                                    "feature_not_in_plan",
                                    "plan_expired",
                                    "account_suspended",
                                    "ip_not_allowed",
                                    "not_found",
                                    "invalid_parameters",
                                    "rate_limited",
                                    "quota_exceeded",
                                    "server_error"
                                ]
                            },
                            "message": {
                                "type": "string"
                            },
                            "request_id": {
                                "type": "string",
                                "nullable": true
                            },
                            "fields": {
                                "type": "object",
                                "description": "Only for invalid_parameters."
                            }
                        }
                    }
                }
            }
        },
        "responses": {
            "Error": {
                "description": "Error. See the code list in the introduction.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            }
        }
    }
}