{
    "openapi": "3.1.0",
    "info": {
        "title": "Sputnik Intelligence API",
        "version": "1.0.0",
        "summary": "Search and read what people are saying in newsletters and podcasts.",
        "description": "Newsletters and podcasts are where named people with real audiences talk to other\npeople. Monitoring tools can't see that conversation, and agents can't reach it:\npodcasts are audio and newsletters live in inboxes. This API turns both into one\nindexed corpus you can search, read, and watch for mentions.\n\nEverything here is also available over MCP, one tool per operation, at\n`https://sputnikintelligence.com/mcp`.\n\n**Conventions that hold everywhere:**\n\n- Every entity is addressed by an opaque `slug`, never a database id.\n- Every list returns `{items, total, next_cursor}`. Follow `next_cursor` until it\n  comes back `null`; a short page does not mean you are done.\n- Every error is `{message, code, errors?}`. Branch on `code`, not on the message.",
        "contact": {
            "name": "Sputnik Intelligence",
            "email": "peter@helpfulintelligence.co"
        }
    },
    "servers": [
        {
            "url": "https://sputnikintelligence.com",
            "description": "Production"
        }
    ],
    "security": [
        {
            "bearerAuth": []
        }
    ],
    "tags": [
        {
            "name": "Posts",
            "description": "The corpus itself: newsletter issues, podcast episodes, blog posts."
        },
        {
            "name": "People",
            "description": "Authors, hosts and guests credited on posts."
        },
        {
            "name": "Sources",
            "description": "The publications we index."
        },
        {
            "name": "Topics",
            "description": "What the corpus is about, extracted off posts."
        },
        {
            "name": "Sponsors",
            "description": "Brands read out as sponsors. Ads that ran, not deals a show signed."
        },
        {
            "name": "Collections",
            "description": "Named sets of publications, used to scope a search."
        },
        {
            "name": "Projects",
            "description": "One thing your team monitors for. Alerts live inside a project."
        },
        {
            "name": "Alerts",
            "description": "Standing searches that tell you when something new matches."
        },
        {
            "name": "Webhooks",
            "description": "Reusable delivery endpoints owned by your team."
        }
    ],
    "paths": {
        "/api/v1/posts": {
            "get": {
                "operationId": "listPosts",
                "tags": [
                    "Posts"
                ],
                "summary": "Browse posts, newest first",
                "description": "A chronological feed. Give at most one scope \u2014 `collection`, `source`,\n`person`, `topic` or `sponsor` \u2014 to narrow it; they are alternative ways of\ncutting the same list, not filters that compose, so passing two is a 422\nwith `code: scope_conflict`.\n\nFor relevance-ranked search, use `GET /api/v1/posts/search`.",
                "parameters": [
                    {
                        "name": "collection",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Collection slug. Restricts to that collection's publications."
                    },
                    {
                        "name": "source",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Publication slug."
                    },
                    {
                        "name": "person",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Person slug. Posts they are credited on."
                    },
                    {
                        "name": "topic",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Topic slug."
                    },
                    {
                        "name": "sponsor",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Sponsor slug. Posts that read the brand out."
                    },
                    {
                        "name": "window",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "24h",
                                "48h",
                                "week",
                                "month",
                                "3months",
                                "year"
                            ],
                            "default": "all"
                        },
                        "description": "A rolling window measured back from now, not a calendar period."
                    },
                    {
                        "name": "include_dead_sources",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "boolean",
                            "default": false
                        },
                        "description": "Include posts from publications we have marked dead (no longer publishing). Archived publications stay excluded either way."
                    },
                    {
                        "$ref": "#/components/parameters/limit"
                    },
                    {
                        "$ref": "#/components/parameters/cursor"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of posts.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/PostList"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/posts/search": {
            "get": {
                "operationId": "searchPosts",
                "tags": [
                    "Posts"
                ],
                "summary": "Full-text search",
                "description": "Ranked by relevance by default, or by recency for a chronological stream of\nmentions.\n\nBare space-separated terms are ANDed, and may match anywhere in a document \u2014\non a two-hour transcript, `comfort food` matches an episode saying \"comfort\"\nin the intro and \"food\" an hour later. Quote a phrase you mean as a phrase.\nQuoted phrases match an exact word sequence; uppercase `AND`/`OR`/`NOT`\ncombine terms; `field:value` scopes to `title`, `body`, `transcript` or\n`author`. Malformed syntax is repaired rather than rejected.\n\nThere is deliberately **no person filter** here. We credit a person on far\ntoo few posts for it to be a filter worth trusting, and a keyword search for\nthe name finds more. Chronological browse still takes `person`, because that\nreads the credits directly rather than the index.",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "minLength": 1
                        },
                        "description": "What to search for."
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "relevance",
                                "recency"
                            ],
                            "default": "relevance"
                        },
                        "description": "Result ordering."
                    },
                    {
                        "name": "collection",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Collection slug. Pass at most one of collection or source."
                    },
                    {
                        "name": "source",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Publication slug."
                    },
                    {
                        "name": "window",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "24h",
                                "48h",
                                "week",
                                "month",
                                "3months",
                                "year"
                            ],
                            "default": "all"
                        },
                        "description": "A rolling window measured back from now."
                    },
                    {
                        "name": "include_dead_sources",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "boolean",
                            "default": false
                        },
                        "description": "Include posts from publications marked dead."
                    },
                    {
                        "name": "source_type",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "One or more of `podcast`, `newsletter`, `blog`, comma-separated and OR'd. What the publication *is*."
                    },
                    {
                        "name": "publishing_platform",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "One or more of `rss`, `substack`, `beehiiv`, `bluesky`, `email`, comma-separated and OR'd. Where it is *hosted*. Independent of source_type: a Substack-hosted podcast is both."
                    },
                    {
                        "name": "language",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "minLength": 2,
                            "maxLength": 2
                        },
                        "description": "Two-letter language code, e.g. `en`."
                    },
                    {
                        "name": "has_transcript",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "boolean"
                        },
                        "description": "Omit for no filter."
                    },
                    {
                        "name": "has_audio",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "boolean"
                        },
                        "description": "Omit for no filter."
                    },
                    {
                        "name": "min_word_count",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "minimum": 0
                        },
                        "description": "Inclusive."
                    },
                    {
                        "name": "min_duration_seconds",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "minimum": 0
                        },
                        "description": "Inclusive. Seconds, so 1200 is twenty minutes."
                    },
                    {
                        "$ref": "#/components/parameters/limit"
                    },
                    {
                        "$ref": "#/components/parameters/cursor"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of results, each with a highlighted `snippet`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/PostList"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/posts/{post}": {
            "get": {
                "operationId": "getPost",
                "tags": [
                    "Posts"
                ],
                "summary": "One post",
                "description": "The full record, including body text where we hold it.",
                "parameters": [
                    {
                        "name": "post",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The post slug."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The post.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/PostDetail"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/posts/{post}/transcript": {
            "get": {
                "operationId": "getPostTranscript",
                "tags": [
                    "Posts"
                ],
                "summary": "A podcast episode as speaker turns",
                "description": "Paged speaker turns, with real names substituted for \"Speaker 1\" wherever we\ncould identify them. This is the only way to read a transcript \u2014 the words are\nnever inlined on the post itself.\n\n`transcript_status` rides alongside the envelope so a caller that gets zero\nturns can tell \"not transcribed yet\" from \"transcribed, but empty\".",
                "parameters": [
                    {
                        "name": "post",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The post slug."
                    },
                    {
                        "$ref": "#/components/parameters/limit"
                    },
                    {
                        "$ref": "#/components/parameters/cursor"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of speaker turns.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/TranscriptPage"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/people": {
            "get": {
                "operationId": "searchPeople",
                "tags": [
                    "People"
                ],
                "summary": "Find a person by name or handle",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "minLength": 1
                        },
                        "description": "A name or handle."
                    },
                    {
                        "$ref": "#/components/parameters/limit"
                    },
                    {
                        "$ref": "#/components/parameters/cursor"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of people.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/PersonList"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/people/{person}": {
            "get": {
                "operationId": "getPerson",
                "tags": [
                    "People"
                ],
                "summary": "One person",
                "description": "Adds what they have been talking about lately and where they appear. `topics` is empty for anyone whose posts predate topic extraction.",
                "parameters": [
                    {
                        "name": "person",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The person slug."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The person.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/PersonDetail"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/sources": {
            "get": {
                "operationId": "searchSources",
                "tags": [
                    "Sources"
                ],
                "summary": "The publications we index",
                "description": "With no `q`, the browsable list of everything we index.",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "minLength": 1
                        },
                        "description": "Optional name filter."
                    },
                    {
                        "$ref": "#/components/parameters/limit"
                    },
                    {
                        "$ref": "#/components/parameters/cursor"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of publications.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SourceList"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/sources/{source}": {
            "get": {
                "operationId": "getSource",
                "tags": [
                    "Sources"
                ],
                "summary": "One publication",
                "description": "Adds what it has been covering lately and which brands have advertised on it.",
                "parameters": [
                    {
                        "name": "source",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The publication slug."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The publication.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/SourceDetail"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/topics": {
            "get": {
                "operationId": "searchTopics",
                "tags": [
                    "Topics"
                ],
                "summary": "What the corpus is about",
                "description": "With `q`, all-time matches for that name; without it, the most-covered topics\nof the last 90 days.\n\n**This index is capped, not paged.** It returns at most 100 rows, `next_cursor`\nis always null, and `total` goes null when the cap was hit. Passing `cursor` is\na 422 \u2014 narrow with `q` instead. Past the first hundred, a ranked list of a\nmillion topics is not something anyone reads, and the query stops being cheap.",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "minLength": 1
                        },
                        "description": "Optional name filter, matched anywhere in the name."
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100,
                            "default": 100
                        },
                        "description": "How many rows. Honoured up to the cap."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Up to 100 topics.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/TopicList"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/topics/{topic}": {
            "get": {
                "operationId": "getTopic",
                "tags": [
                    "Topics"
                ],
                "summary": "One topic",
                "description": "Adds the publications covering it most and the people credited on its posts. For the posts themselves, use `GET /api/v1/posts?topic=<slug>`.",
                "parameters": [
                    {
                        "name": "topic",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The topic slug. Names are display text; do not pass one as a key."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The topic.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/TopicDetail"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/sponsors": {
            "get": {
                "operationId": "searchSponsors",
                "tags": [
                    "Sponsors"
                ],
                "summary": "Brands read out as sponsors",
                "description": "With `q`, all-time matches for that brand name, matched case-insensitively;\nwithout it, the most-heard sponsors of the last 90 days.\n\nCapped rather than paged, exactly like topics.\n\n**Read these as ads that ran, not deals a show signed.** Programmatic insertion\nputs spots into feeds the publisher never sold \u2014 a physics channel's transcript\nreads out ads a streaming platform placed, not sponsors it found.",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "minLength": 1
                        },
                        "description": "Optional brand-name filter."
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100,
                            "default": 100
                        },
                        "description": "How many rows. Honoured up to the cap."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Up to 100 sponsors.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SponsorList"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/sponsors/{sponsor}": {
            "get": {
                "operationId": "getSponsor",
                "tags": [
                    "Sponsors"
                ],
                "summary": "One sponsor",
                "description": "Adds the shows the brand has been heard on, most appearances first.",
                "parameters": [
                    {
                        "name": "sponsor",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The sponsor slug."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The sponsor.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/SponsorDetail"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/collections": {
            "get": {
                "operationId": "listCollections",
                "tags": [
                    "Collections"
                ],
                "summary": "Your team's collections, and ours",
                "description": "Both the collections your team owns and the global ones Sputnik curates. `is_global` tells them apart; global ones are readable by everyone and editable by no one.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/limit"
                    },
                    {
                        "$ref": "#/components/parameters/cursor"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of collections.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CollectionList"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "post": {
                "operationId": "createCollection",
                "tags": [
                    "Collections"
                ],
                "summary": "Create a collection",
                "description": "Created empty. Add publications with `POST /collections/{collection}/sources`.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "maxLength": 255
                                    },
                                    "description": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "maxLength": 1000
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The new collection.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Collection"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/collections/{collection}": {
            "get": {
                "operationId": "getCollection",
                "tags": [
                    "Collections"
                ],
                "summary": "One collection, with its publications",
                "parameters": [
                    {
                        "name": "collection",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The collection slug."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The collection.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/CollectionDetail"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "patch": {
                "operationId": "updateCollection",
                "tags": [
                    "Collections"
                ],
                "summary": "Rename a collection",
                "description": "Only the given fields change. Which publications are in it is a separate thing.",
                "parameters": [
                    {
                        "name": "collection",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The collection slug."
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "maxLength": 255
                                    },
                                    "description": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "maxLength": 1000
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The updated collection.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Collection"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "delete": {
                "operationId": "deleteCollection",
                "tags": [
                    "Collections"
                ],
                "summary": "Delete a collection",
                "description": "Removes the set, not the publications in it.",
                "parameters": [
                    {
                        "name": "collection",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The collection slug."
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Deleted."
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/collections/{collection}/sources": {
            "post": {
                "operationId": "addSourcesToCollection",
                "tags": [
                    "Collections"
                ],
                "summary": "Add publications to a collection",
                "description": "Adding one already in it is a no-op, so this is safe to retry.",
                "parameters": [
                    {
                        "name": "collection",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The collection slug."
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "source_slugs"
                                ],
                                "properties": {
                                    "source_slugs": {
                                        "type": "array",
                                        "minItems": 1,
                                        "items": {
                                            "type": "string"
                                        },
                                        "description": "Publication slugs, from search_sources."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The collection, with its new count.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Collection"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/collections/{collection}/sources/{source}": {
            "delete": {
                "operationId": "removeSourceFromCollection",
                "tags": [
                    "Collections"
                ],
                "summary": "Remove a publication from a collection",
                "parameters": [
                    {
                        "name": "collection",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The collection slug."
                    },
                    {
                        "name": "source",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The publication slug."
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Removed."
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/projects": {
            "get": {
                "operationId": "listProjects",
                "tags": [
                    "Projects"
                ],
                "summary": "What your team monitors for",
                "description": "A project is usually one of your own customers. Archived ones are hidden unless you ask for them.",
                "parameters": [
                    {
                        "name": "include_archived",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "boolean",
                            "default": false
                        },
                        "description": "Include archived projects."
                    },
                    {
                        "$ref": "#/components/parameters/limit"
                    },
                    {
                        "$ref": "#/components/parameters/cursor"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of projects.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ProjectList"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "post": {
                "operationId": "createProject",
                "tags": [
                    "Projects"
                ],
                "summary": "Create a project",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ProjectInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The new project.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Project"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/projects/{project}": {
            "get": {
                "operationId": "getProject",
                "tags": [
                    "Projects"
                ],
                "summary": "One project",
                "parameters": [
                    {
                        "name": "project",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The project slug."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The project.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Project"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "patch": {
                "operationId": "updateProject",
                "tags": [
                    "Projects"
                ],
                "summary": "Update or archive a project",
                "description": "Setting `is_active` to false archives it and switches off every alert in it. Setting it back to true restores the project but leaves those alerts off \u2014 turning monitoring back on should be a decision, not a side effect.",
                "parameters": [
                    {
                        "name": "project",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The project slug."
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ProjectInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The updated project.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Project"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "delete": {
                "operationId": "deleteProject",
                "tags": [
                    "Projects"
                ],
                "summary": "Delete a project",
                "description": "Takes its alerts and their hits with it. Archive instead if you want the history.",
                "parameters": [
                    {
                        "name": "project",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The project slug."
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Deleted."
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/alerts": {
            "get": {
                "operationId": "listAlerts",
                "tags": [
                    "Alerts"
                ],
                "summary": "Your team's alerts",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/limit"
                    },
                    {
                        "$ref": "#/components/parameters/cursor"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of alerts.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AlertList"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "post": {
                "operationId": "createAlert",
                "tags": [
                    "Alerts"
                ],
                "summary": "Create an alert",
                "description": "An alert belongs to a project and holds up to ten saved searches; a post hits\nthe alert if any of them matches.\n\n`search` is a convenience that creates the alert's first saved search in the\nsame call, so \"watch for this\" is one request. It is nested because an alert\nand its search both have a name \u2014 `search.q` and `search.name` are exactly\nwhat the searches endpoint takes.\n\nA new alert delivers nowhere until you give it a destination. That state is\nlegal, and the app flags it.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name",
                                    "project"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "maxLength": 120,
                                        "description": "Shown in notifications, e.g. \"Competitor: Acme\"."
                                    },
                                    "project": {
                                        "type": "string",
                                        "description": "Project slug. An archived project, or one belonging to another team, is a 422."
                                    },
                                    "is_active": {
                                        "type": "boolean",
                                        "default": true
                                    },
                                    "search": {
                                        "type": "object",
                                        "description": "Optional first saved search.",
                                        "required": [
                                            "q"
                                        ],
                                        "properties": {
                                            "q": {
                                                "type": "string",
                                                "maxLength": 2000,
                                                "description": "Same syntax as GET /posts/search."
                                            },
                                            "name": {
                                                "type": [
                                                    "string",
                                                    "null"
                                                ],
                                                "maxLength": 120,
                                                "description": "Label, shown on hits so you can tell which search fired."
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The new alert.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Alert"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/alerts/{alert}": {
            "get": {
                "operationId": "getAlert",
                "tags": [
                    "Alerts"
                ],
                "summary": "One alert",
                "description": "With its searches, its destinations and its hit count. The hits themselves come from `GET /alert-hits`.",
                "parameters": [
                    {
                        "name": "alert",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The alert slug."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The alert.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Alert"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "patch": {
                "operationId": "updateAlert",
                "tags": [
                    "Alerts"
                ],
                "summary": "Update an alert",
                "description": "Changes only what is true of the notification \u2014 its name, its project, whether it is on. What it looks for lives on its searches; where it delivers on its destinations.",
                "parameters": [
                    {
                        "name": "alert",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The alert slug."
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "maxLength": 120
                                    },
                                    "project": {
                                        "type": "string",
                                        "description": "Move the alert to another project."
                                    },
                                    "is_active": {
                                        "type": "boolean"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The updated alert.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Alert"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "delete": {
                "operationId": "deleteAlert",
                "tags": [
                    "Alerts"
                ],
                "summary": "Delete an alert",
                "description": "Takes its hits with it. Set `is_active` to false instead to stop it matching while keeping the history.",
                "parameters": [
                    {
                        "name": "alert",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The alert slug."
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Deleted."
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/alerts/{alert}/searches": {
            "get": {
                "operationId": "listAlertSearches",
                "tags": [
                    "Alerts"
                ],
                "summary": "What an alert looks for",
                "parameters": [
                    {
                        "name": "alert",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The alert slug."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The alert's saved searches. Small and unpaged, but the envelope is the same.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AlertSearchList"
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "post": {
                "operationId": "createAlertSearch",
                "tags": [
                    "Alerts"
                ],
                "summary": "Add a saved search",
                "description": "Takes `q` and the same filter names `GET /posts/search` takes, so a search\nthat worked lifts straight into an alert without renaming anything.\n\nA search added today starts finding hits on the next run, which looks back a\nday. It does not reach further back: an alert reports new things, and the\nhistory of a query belongs in search.\n\nAn alert holds ten searches; the eleventh is a 422.",
                "parameters": [
                    {
                        "name": "alert",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The alert slug."
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/AlertSearchInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The new saved search.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/AlertSearch"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/alerts/{alert}/searches/{search}": {
            "patch": {
                "operationId": "updateAlertSearch",
                "tags": [
                    "Alerts"
                ],
                "summary": "Edit a saved search",
                "description": "Applies from the next run onwards. It does not re-run the new definition over the past \u2014 that would report old posts as news.",
                "parameters": [
                    {
                        "name": "alert",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The alert slug."
                    },
                    {
                        "name": "search",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "The search id, from the list endpoint. Resolved through its alert, so another team's id is a 404."
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/AlertSearchInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The updated search.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/AlertSearch"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "delete": {
                "operationId": "deleteAlertSearch",
                "tags": [
                    "Alerts"
                ],
                "summary": "Switch a saved search off",
                "description": "Deactivates rather than deletes: hits exist because this search found them, and removing it outright orphans that explanation. PATCH `is_active` back to true to restore it.",
                "parameters": [
                    {
                        "name": "alert",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The alert slug."
                    },
                    {
                        "name": "search",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "The search id."
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Deactivated."
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/alerts/{alert}/destinations": {
            "get": {
                "operationId": "listAlertDestinations",
                "tags": [
                    "Alerts"
                ],
                "summary": "Where an alert delivers",
                "parameters": [
                    {
                        "name": "alert",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The alert slug."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Its destinations.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AlertDestinationList"
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "post": {
                "operationId": "createAlertDestination",
                "tags": [
                    "Alerts"
                ],
                "summary": "Point an alert somewhere",
                "description": "Give exactly one of `email` or `webhook`. The channel comes from the webhook rather than being passed in \u2014 the two must agree, and this is the only way to guarantee it.\n\nAdding a destination does not replay history: hits already delivered stay delivered, so connecting a webhook in week three does not fire hundreds of events about things you have already seen.",
                "parameters": [
                    {
                        "name": "alert",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The alert slug."
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "email": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "format": "email"
                                    },
                                    "webhook": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "description": "Slug of one of your team's webhooks."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The new destination.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/AlertDestination"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/alerts/{alert}/destinations/{destination}": {
            "delete": {
                "operationId": "deleteAlertDestination",
                "tags": [
                    "Alerts"
                ],
                "summary": "Stop delivering to one destination",
                "parameters": [
                    {
                        "name": "alert",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The alert slug."
                    },
                    {
                        "name": "destination",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "The destination id, from the list endpoint."
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Removed."
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/alert-hits": {
            "get": {
                "operationId": "listAlertHits",
                "tags": [
                    "Alerts"
                ],
                "summary": "What your alerts have found",
                "description": "A resumable stream, not an ordinary page. `next_cursor` is a resume token:\nstore it, pass it back as `cursor`, and you get only what has arrived since.\nIt keeps coming back non-null even when there is nothing new, so poll it\nrather than waiting for null.\n\nEach hit carries the post, the alert, and which of its searches matched.",
                "parameters": [
                    {
                        "name": "alert",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Restrict to one alert, by slug."
                    },
                    {
                        "$ref": "#/components/parameters/limit"
                    },
                    {
                        "$ref": "#/components/parameters/cursor"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of hits, oldest first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AlertHitList"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/webhooks": {
            "get": {
                "operationId": "listTeamWebhooks",
                "tags": [
                    "Webhooks"
                ],
                "summary": "Your team's delivery endpoints",
                "description": "Registered once for the team and reusable by any of its alerts, in any project. The signing secret comes back on every read.",
                "responses": {
                    "200": {
                        "description": "The webhooks.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/TeamWebhookList"
                                }
                            }
                        }
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "post": {
                "operationId": "createTeamWebhook",
                "tags": [
                    "Webhooks"
                ],
                "summary": "Register an endpoint",
                "description": "Registering one delivers nothing on its own \u2014 point an alert at it with `POST /alerts/{alert}/destinations`.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name",
                                    "url"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "maxLength": 120
                                    },
                                    "url": {
                                        "type": "string",
                                        "format": "uri",
                                        "maxLength": 2048,
                                        "description": "For Slack, its incoming webhook URL."
                                    },
                                    "channel": {
                                        "type": "string",
                                        "enum": [
                                            "webhook",
                                            "slack"
                                        ],
                                        "default": "webhook",
                                        "description": "webhook sends signed JSON; slack sends Block Kit."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The new webhook, with its signing secret.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/TeamWebhook"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/api/v1/webhooks/{webhook}": {
            "patch": {
                "operationId": "updateTeamWebhook",
                "tags": [
                    "Webhooks"
                ],
                "summary": "Rename, repoint, or switch off",
                "description": "Switching one back on also clears its failure streak, so an endpoint you have just fixed gets a fresh run of attempts rather than deactivating itself on its very next failure.",
                "parameters": [
                    {
                        "name": "webhook",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The webhook slug."
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "maxLength": 120
                                    },
                                    "url": {
                                        "type": "string",
                                        "format": "uri",
                                        "maxLength": 2048
                                    },
                                    "is_active": {
                                        "type": "boolean",
                                        "description": "false stops delivery to this endpoint."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The updated webhook.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/TeamWebhook"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "delete": {
                "operationId": "deleteTeamWebhook",
                "tags": [
                    "Webhooks"
                ],
                "summary": "Delete an endpoint",
                "description": "Blocked with a 422 while any alert still delivers here: cascading would silently mute those alerts, and you would find out by not being told about something. PATCH `is_active` to false instead.",
                "parameters": [
                    {
                        "name": "webhook",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "The webhook slug."
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Deleted."
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthenticated"
                    },
                    "402": {
                        "$ref": "#/components/responses/NoPlan"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "bearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "description": "An API key, created in the app under Settings \u2192 API keys, sent as\n`Authorization: Bearer <key>`.\n\nA key belongs to the team it was created for and only ever acts for that\nteam \u2014 never whichever team its creator last opened in the web UI. Someone in\ntwo teams holds two keys, and neither reaches the other team's collections,\nprojects or alerts."
            }
        },
        "parameters": {
            "limit": {
                "name": "limit",
                "in": "query",
                "required": false,
                "schema": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100
                },
                "description": "Rows per page, 1\u2013100. Defaults to 50, or 20 for people and publications."
            },
            "cursor": {
                "name": "cursor",
                "in": "query",
                "required": false,
                "schema": {
                    "type": "string"
                },
                "description": "The `next_cursor` from the previous response. Opaque \u2014 do not construct one. Omit for the first page."
            }
        },
        "responses": {
            "ValidationFailed": {
                "description": "The request was rejected. `code` says why: `validation_failed` for a bad parameter, `invalid_cursor` for a cursor we did not issue, `scope_conflict` for mutually exclusive scopes passed together.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "NotFound": {
                "description": "No such slug. `code` is `not_found`. If you passed a numeric id, the message says so \u2014 this API addresses everything by slug.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "Unauthenticated": {
                "description": "Missing, malformed or revoked API key. `code` is `unauthenticated`.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "Forbidden": {
                "description": "The key is valid but its team may not touch this row. `code` is `forbidden`.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "NoPlan": {
                "description": "The team has no active plan. `code` is `no_plan`. Unlike a rate limit, retrying will not help.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "RateLimited": {
                "description": "Too many requests. `code` is `rate_limited`; wait the number of seconds in the `Retry-After` header.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                },
                "headers": {
                    "Retry-After": {
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Seconds to wait."
                    }
                }
            }
        },
        "schemas": {
            "Error": {
                "type": "object",
                "description": "Every failure, on every endpoint, in one shape.",
                "required": [
                    "message",
                    "code"
                ],
                "properties": {
                    "message": {
                        "type": "string",
                        "description": "Human-readable. Do not branch on it."
                    },
                    "code": {
                        "type": "string",
                        "description": "What went wrong, for a program to branch on.",
                        "enum": [
                            "validation_failed",
                            "invalid_cursor",
                            "scope_conflict",
                            "not_found",
                            "unauthenticated",
                            "forbidden",
                            "no_plan",
                            "rate_limited",
                            "quote_not_verbatim",
                            "server_error"
                        ]
                    },
                    "errors": {
                        "type": "object",
                        "description": "Per-field messages, present on validation failures.",
                        "additionalProperties": {
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        }
                    }
                }
            },
            "Post": {
                "type": "object",
                "description": "A newsletter issue, podcast episode or blog post, as it appears in a list.",
                "required": [
                    "slug",
                    "sputnik_url",
                    "title",
                    "link",
                    "published_at"
                ],
                "properties": {
                    "slug": {
                        "type": "string",
                        "description": "The key. Pass this back, not the title."
                    },
                    "sputnik_url": {
                        "type": "string",
                        "format": "uri",
                        "description": "This post's page on Sputnik. Link to it verbatim rather than building a URL from the slug."
                    },
                    "title": {
                        "type": "string"
                    },
                    "link": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "uri",
                        "description": "The publisher's own URL. Not the same as sputnik_url."
                    },
                    "author": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "As the publication declared it, unparsed."
                    },
                    "published_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "snippet": {
                        "type": "string",
                        "description": "Search results only: the matched text, with `<b>` around the hit."
                    },
                    "excerpt": {
                        "type": "string"
                    },
                    "source": {
                        "$ref": "#/components/schemas/SourceRef"
                    },
                    "transcript_status": {
                        "type": "string",
                        "description": "Podcasts only."
                    }
                }
            },
            "PostDetail": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/Post"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "text_content": {
                                "type": "string",
                                "description": "The body, where we hold it."
                            },
                            "categories": {
                                "type": "array",
                                "items": {
                                    "type": "string"
                                },
                                "description": "The publication's own tags, unnormalised and sparse."
                            },
                            "enclosure_url": {
                                "type": "string",
                                "format": "uri",
                                "description": "The audio file, for a podcast episode."
                            },
                            "people": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/PersonWithRole"
                                }
                            },
                            "data_points": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/DataPoint"
                                }
                            }
                        }
                    }
                ]
            },
            "SourceRef": {
                "type": [
                    "object",
                    "null"
                ],
                "description": "A publication, named just enough to identify it.",
                "properties": {
                    "slug": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string"
                    }
                }
            },
            "Person": {
                "type": "object",
                "required": [
                    "slug",
                    "sputnik_url",
                    "name"
                ],
                "properties": {
                    "slug": {
                        "type": "string"
                    },
                    "sputnik_url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "name": {
                        "type": "string"
                    },
                    "avatar_url": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "uri"
                    },
                    "substack_handle": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "posts_count": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "bio": {
                        "type": "string"
                    }
                }
            },
            "PersonWithRole": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/Person"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "role": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "How they appear on this post: author, host, guest."
                            }
                        }
                    }
                ]
            },
            "PersonDetail": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/Person"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data_points": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/DataPoint"
                                }
                            },
                            "appearances": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/Appearance"
                                }
                            },
                            "topics": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/TopicSummary"
                                },
                                "description": "What they have been talking about lately, from their newest posts. Empty for anyone whose posts predate topic extraction."
                            }
                        }
                    }
                ]
            },
            "Appearance": {
                "type": "object",
                "description": "A publication this person turns up on, and how.",
                "properties": {
                    "source": {
                        "$ref": "#/components/schemas/SourceSummary"
                    },
                    "roles": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "posts_count": {
                        "type": "integer"
                    },
                    "last_published_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "SourceSummary": {
                "type": "object",
                "properties": {
                    "slug": {
                        "type": "string"
                    },
                    "sputnik_url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "name": {
                        "type": "string"
                    },
                    "type": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "enum": [
                            "podcast",
                            "newsletter",
                            "blog",
                            null
                        ]
                    },
                    "avatar_url": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "uri"
                    }
                }
            },
            "Source": {
                "type": "object",
                "description": "A publication. One publication of one type \u2014 a show, a newsletter, a blog.",
                "required": [
                    "slug",
                    "sputnik_url",
                    "name"
                ],
                "properties": {
                    "slug": {
                        "type": "string"
                    },
                    "sputnik_url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "name": {
                        "type": "string"
                    },
                    "type": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "enum": [
                            "podcast",
                            "newsletter",
                            "blog",
                            null
                        ]
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "homepage_url": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "uri"
                    },
                    "avatar_url": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "uri"
                    },
                    "authority_score": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Our judgment of how much weight this publication carries."
                    },
                    "liveness": {
                        "type": "string",
                        "enum": [
                            "active",
                            "dormant",
                            "dead",
                            "broken",
                            "pending"
                        ],
                        "description": "Whether it is still publishing."
                    },
                    "content_depth": {
                        "type": "string",
                        "description": "How substantial its posts are."
                    },
                    "apple_id": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "spotify_id": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "posts_count": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "feeds_count": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "first_post_published_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "last_post_published_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "SourceDetail": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/Source"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data_points": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/DataPoint"
                                }
                            },
                            "topics": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/TopicSummary"
                                },
                                "description": "What it has been covering lately."
                            },
                            "sponsors": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/SponsorSummary"
                                },
                                "description": "Brands heard on its recent posts."
                            }
                        }
                    }
                ]
            },
            "DataPoint": {
                "type": "object",
                "description": "One enriched fact, with where it came from and when.",
                "properties": {
                    "key": {
                        "type": "string"
                    },
                    "value": {
                        "description": "Whatever the fact is."
                    },
                    "source": {
                        "type": "string",
                        "description": "Where we got it."
                    },
                    "fetched_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "TopicSummary": {
                "type": "object",
                "required": [
                    "slug",
                    "sputnik_url",
                    "name",
                    "posts_count"
                ],
                "properties": {
                    "slug": {
                        "type": "string",
                        "description": "The key."
                    },
                    "sputnik_url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "name": {
                        "type": "string",
                        "description": "Lowercase display text. Not a key."
                    },
                    "posts_count": {
                        "type": "integer"
                    }
                }
            },
            "TopicDetail": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/TopicSummary"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "sources": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/SourceSummary"
                                },
                                "description": "Which publications cover it most."
                            },
                            "people": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/TopicPerson"
                                },
                                "description": "Who is credited on its posts."
                            }
                        }
                    }
                ]
            },
            "TopicPerson": {
                "type": "object",
                "properties": {
                    "slug": {
                        "type": "string"
                    },
                    "sputnik_url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "name": {
                        "type": "string"
                    },
                    "posts_count": {
                        "type": "integer"
                    },
                    "last_posted_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "roles": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    }
                }
            },
            "SponsorSummary": {
                "type": "object",
                "required": [
                    "slug",
                    "sputnik_url",
                    "name",
                    "posts_count"
                ],
                "properties": {
                    "slug": {
                        "type": "string"
                    },
                    "sputnik_url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "name": {
                        "type": "string",
                        "description": "The brand's own casing."
                    },
                    "posts_count": {
                        "type": "integer",
                        "description": "Posts that read it out."
                    }
                }
            },
            "SponsorDetail": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/SponsorSummary"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "sources_count": {
                                "type": "integer",
                                "description": "How many publications have run it. Says when the capped `sources` list is short of the whole answer."
                            },
                            "sources": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/SourceSummary"
                                },
                                "description": "Where the brand advertises, most appearances first, capped at 100."
                            }
                        }
                    }
                ]
            },
            "TranscriptTurn": {
                "type": "object",
                "description": "One speaker's continuous stretch of talking.",
                "required": [
                    "speaker",
                    "kind",
                    "text"
                ],
                "properties": {
                    "speaker": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "The real name where we identified it, otherwise a generic label."
                    },
                    "kind": {
                        "type": "string",
                        "description": "What we make of the speaker: host, guest, or unknown."
                    },
                    "text": {
                        "type": "string",
                        "description": "The turn as a paragraph."
                    }
                }
            },
            "Collection": {
                "type": "object",
                "description": "A named set of publications, used to scope a search.",
                "required": [
                    "slug",
                    "name"
                ],
                "properties": {
                    "slug": {
                        "type": "string"
                    },
                    "sputnik_url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "name": {
                        "type": "string"
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "is_global": {
                        "type": "boolean",
                        "description": "True for the collections Sputnik curates: readable by everyone, editable by no one."
                    },
                    "sources_count": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "posts_count": {
                        "type": "integer",
                        "description": "Detail responses only."
                    }
                }
            },
            "CollectionDetail": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/Collection"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "sources": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/Source"
                                },
                                "description": "The publications in it. Fully archived ones are excluded, here and in the counts."
                            }
                        }
                    }
                ]
            },
            "ProjectInput": {
                "type": "object",
                "required": [
                    "name"
                ],
                "properties": {
                    "name": {
                        "type": "string",
                        "maxLength": 120
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 2000,
                        "description": "What this project is watching for."
                    },
                    "is_active": {
                        "type": "boolean",
                        "default": true,
                        "description": "false archives it and switches off every alert in it."
                    }
                }
            },
            "Project": {
                "type": "object",
                "description": "One thing your team monitors for, usually one of your own customers.",
                "required": [
                    "slug",
                    "name",
                    "is_active"
                ],
                "properties": {
                    "slug": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string"
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "is_active": {
                        "type": "boolean",
                        "description": "False means archived."
                    },
                    "alerts_count": {
                        "type": "integer"
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "Alert": {
                "type": "object",
                "description": "A standing set of searches that tells you when something new matches.",
                "required": [
                    "slug",
                    "name",
                    "is_active"
                ],
                "properties": {
                    "slug": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string"
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "project": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "properties": {
                            "slug": {
                                "type": "string"
                            },
                            "name": {
                                "type": "string"
                            }
                        }
                    },
                    "searches": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/AlertSearch"
                        }
                    },
                    "destinations": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/AlertDestination"
                        }
                    },
                    "hits_count": {
                        "type": "integer"
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "AlertSearchInput": {
                "type": "object",
                "description": "The filter names are exactly the ones GET /posts/search takes, so a search that worked lifts straight in. Pass null to clear a filter. Scope is named by slug; give at most one of collection/source/feed.",
                "properties": {
                    "q": {
                        "type": "string",
                        "maxLength": 2000,
                        "description": "Required when creating."
                    },
                    "name": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 120,
                        "description": "Shown on hits so you can tell which search fired."
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "collection": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "source": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "feed": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "source_type": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "publishing_platform": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "language": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "minLength": 2,
                        "maxLength": 2
                    },
                    "has_transcript": {
                        "type": [
                            "boolean",
                            "null"
                        ]
                    },
                    "has_audio": {
                        "type": [
                            "boolean",
                            "null"
                        ]
                    },
                    "min_word_count": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "minimum": 0
                    },
                    "min_duration_seconds": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "minimum": 0
                    }
                }
            },
            "AlertSearch": {
                "type": "object",
                "description": "One saved search on an alert.",
                "required": [
                    "id",
                    "query",
                    "is_active"
                ],
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "The key for the update and delete endpoints."
                    },
                    "name": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "position": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "query": {
                        "type": "string",
                        "description": "What it searches for. Sent as `q`, stored and returned as `query`."
                    },
                    "filters": {
                        "type": "object",
                        "description": "Only the filters actually set, by slug where they name an entity.",
                        "additionalProperties": true
                    },
                    "last_run_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "AlertDestination": {
                "type": "object",
                "description": "Somewhere one alert delivers.",
                "required": [
                    "id",
                    "channel",
                    "is_active"
                ],
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "The key for the delete endpoint."
                    },
                    "channel": {
                        "type": "string",
                        "enum": [
                            "email",
                            "webhook",
                            "slack"
                        ]
                    },
                    "target": {
                        "type": "string",
                        "description": "The address or webhook name, for display."
                    },
                    "email": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "email"
                    },
                    "webhook": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "The webhook slug, when this delivers to one."
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "is_delivering": {
                        "type": "boolean",
                        "description": "False when the destination is on but its webhook has switched itself off after repeated failures. This is the field that tells you an alert has gone quiet for a reason you can fix."
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "TeamWebhook": {
                "type": "object",
                "description": "A reusable delivery endpoint owned by your team.",
                "required": [
                    "slug",
                    "name",
                    "url",
                    "channel",
                    "is_active"
                ],
                "properties": {
                    "slug": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string"
                    },
                    "channel": {
                        "type": "string",
                        "enum": [
                            "webhook",
                            "slack"
                        ]
                    },
                    "url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "secret": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "The signing secret, returned on every read. Verify the `webhook-signature` header with it (Standard Webhooks). Endpoints that do not check signatures, such as Zapier, can ignore it."
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "verified_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "last_success_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "last_failure_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "consecutive_failures": {
                        "type": "integer",
                        "description": "Cleared when you switch a deactivated webhook back on."
                    },
                    "deactivated_reason": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Why we switched it off, when we did."
                    },
                    "alerts_count": {
                        "type": "integer",
                        "description": "How many alert destinations point here. Non-zero means DELETE is blocked."
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "AlertHit": {
                "type": "object",
                "description": "One post that matched one of your alerts.",
                "properties": {
                    "alert": {
                        "type": "object",
                        "properties": {
                            "slug": {
                                "type": "string"
                            },
                            "name": {
                                "type": "string"
                            }
                        }
                    },
                    "matched_searches": {
                        "type": "array",
                        "description": "Which of the alert's searches fired. An alert with several searches tells you which one this is about.",
                        "items": {
                            "type": "object",
                            "properties": {
                                "id": {
                                    "type": "integer"
                                },
                                "name": {
                                    "type": "string"
                                }
                            }
                        }
                    },
                    "snippet": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "The matched text in context \u2014 the evidence, so a hit is forwardable as-is."
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time",
                        "description": "When we found it, not when it was published."
                    },
                    "post": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "properties": {
                            "slug": {
                                "type": "string"
                            },
                            "sputnik_url": {
                                "type": "string",
                                "format": "uri"
                            },
                            "title": {
                                "type": "string"
                            },
                            "link": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "format": "uri"
                            },
                            "published_at": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "format": "date-time"
                            },
                            "source": {
                                "$ref": "#/components/schemas/SourceSummary"
                            }
                        }
                    }
                }
            },
            "CollectionList": {
                "type": "object",
                "description": "A page of collections.",
                "required": [
                    "items",
                    "total",
                    "next_cursor"
                ],
                "properties": {
                    "items": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Collection"
                        }
                    },
                    "total": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Total matching rows when it is cheap to know; null when it is not."
                    },
                    "next_cursor": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Pass back as `cursor` for the next page. Null means you have everything \u2014 follow it until null rather than watching for a short page."
                    }
                }
            },
            "ProjectList": {
                "type": "object",
                "description": "A page of projects.",
                "required": [
                    "items",
                    "total",
                    "next_cursor"
                ],
                "properties": {
                    "items": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Project"
                        }
                    },
                    "total": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Total matching rows when it is cheap to know; null when it is not."
                    },
                    "next_cursor": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Pass back as `cursor` for the next page. Null means you have everything \u2014 follow it until null rather than watching for a short page."
                    }
                }
            },
            "AlertList": {
                "type": "object",
                "description": "A page of alerts.",
                "required": [
                    "items",
                    "total",
                    "next_cursor"
                ],
                "properties": {
                    "items": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Alert"
                        }
                    },
                    "total": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Total matching rows when it is cheap to know; null when it is not."
                    },
                    "next_cursor": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Pass back as `cursor` for the next page. Null means you have everything \u2014 follow it until null rather than watching for a short page."
                    }
                }
            },
            "AlertSearchList": {
                "type": "object",
                "description": "An alert's saved searches. Small and unpaged: `next_cursor` is always null.",
                "required": [
                    "items",
                    "total",
                    "next_cursor"
                ],
                "properties": {
                    "items": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/AlertSearch"
                        }
                    },
                    "total": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Total matching rows when it is cheap to know; null when it is not."
                    },
                    "next_cursor": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Pass back as `cursor` for the next page. Null means you have everything \u2014 follow it until null rather than watching for a short page."
                    }
                }
            },
            "AlertDestinationList": {
                "type": "object",
                "description": "An alert's destinations. Small and unpaged.",
                "required": [
                    "items",
                    "total",
                    "next_cursor"
                ],
                "properties": {
                    "items": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/AlertDestination"
                        }
                    },
                    "total": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Total matching rows when it is cheap to know; null when it is not."
                    },
                    "next_cursor": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Pass back as `cursor` for the next page. Null means you have everything \u2014 follow it until null rather than watching for a short page."
                    }
                }
            },
            "TeamWebhookList": {
                "type": "object",
                "description": "The team's webhooks. Small and unpaged.",
                "required": [
                    "items",
                    "total",
                    "next_cursor"
                ],
                "properties": {
                    "items": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/TeamWebhook"
                        }
                    },
                    "total": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Total matching rows when it is cheap to know; null when it is not."
                    },
                    "next_cursor": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Pass back as `cursor` for the next page. Null means you have everything \u2014 follow it until null rather than watching for a short page."
                    }
                }
            },
            "AlertHitList": {
                "type": "object",
                "description": "A page of hits. `next_cursor` is a resume token, not an end marker.",
                "required": [
                    "items",
                    "total",
                    "next_cursor"
                ],
                "properties": {
                    "items": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/AlertHit"
                        }
                    },
                    "total": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Total matching rows when it is cheap to know; null when it is not."
                    },
                    "next_cursor": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Pass back as `cursor` for the next page. Null means you have everything \u2014 follow it until null rather than watching for a short page."
                    }
                }
            },
            "PostList": {
                "type": "object",
                "description": "A page of posts.",
                "required": [
                    "items",
                    "total",
                    "next_cursor"
                ],
                "properties": {
                    "items": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Post"
                        }
                    },
                    "total": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Total matching rows when it is cheap to know; null when it is not."
                    },
                    "next_cursor": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Pass back as `cursor` for the next page. Null means you have everything \u2014 follow it until null rather than watching for a short page."
                    }
                }
            },
            "PersonList": {
                "type": "object",
                "description": "A page of people.",
                "required": [
                    "items",
                    "total",
                    "next_cursor"
                ],
                "properties": {
                    "items": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Person"
                        }
                    },
                    "total": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Total matching rows when it is cheap to know; null when it is not."
                    },
                    "next_cursor": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Pass back as `cursor` for the next page. Null means you have everything \u2014 follow it until null rather than watching for a short page."
                    }
                }
            },
            "SourceList": {
                "type": "object",
                "description": "A page of publications.",
                "required": [
                    "items",
                    "total",
                    "next_cursor"
                ],
                "properties": {
                    "items": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Source"
                        }
                    },
                    "total": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Total matching rows when it is cheap to know; null when it is not."
                    },
                    "next_cursor": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Pass back as `cursor` for the next page. Null means you have everything \u2014 follow it until null rather than watching for a short page."
                    }
                }
            },
            "TopicList": {
                "type": "object",
                "description": "Up to 100 topics. `next_cursor` is always null.",
                "required": [
                    "items",
                    "total",
                    "next_cursor"
                ],
                "properties": {
                    "items": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/TopicSummary"
                        }
                    },
                    "total": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Total matching rows when it is cheap to know; null when it is not."
                    },
                    "next_cursor": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Pass back as `cursor` for the next page. Null means you have everything \u2014 follow it until null rather than watching for a short page."
                    }
                }
            },
            "SponsorList": {
                "type": "object",
                "description": "Up to 100 sponsors. `next_cursor` is always null.",
                "required": [
                    "items",
                    "total",
                    "next_cursor"
                ],
                "properties": {
                    "items": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/SponsorSummary"
                        }
                    },
                    "total": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Total matching rows when it is cheap to know; null when it is not."
                    },
                    "next_cursor": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Pass back as `cursor` for the next page. Null means you have everything \u2014 follow it until null rather than watching for a short page."
                    }
                }
            },
            "TranscriptPage": {
                "allOf": [
                    {
                        "type": "object",
                        "description": "A page of speaker turns.",
                        "required": [
                            "items",
                            "total",
                            "next_cursor"
                        ],
                        "properties": {
                            "items": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/TranscriptTurn"
                                }
                            },
                            "total": {
                                "type": [
                                    "integer",
                                    "null"
                                ],
                                "description": "Total matching rows when it is cheap to know; null when it is not."
                            },
                            "next_cursor": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "Pass back as `cursor` for the next page. Null means you have everything \u2014 follow it until null rather than watching for a short page."
                            }
                        }
                    },
                    {
                        "type": "object",
                        "properties": {
                            "transcript_status": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "Lets a caller with zero turns tell \"not transcribed yet\" from \"transcribed, but empty\"."
                            }
                        }
                    }
                ]
            }
        }
    }
}