{
  "openapi": "3.1.0",
  "info": {
    "title": "ThreadAPI API",
    "version": "1.0.0",
    "description": "Public REST API for billing, user balance, and Reddit data extraction.",
    "license": {
      "name": "MIT",
      "identifier": "MIT"
    }
  },
  "servers": [
    {
      "url": "https://api.threadapi.dev",
      "description": "Production API"
    },
    {
      "url": "https://staging.threadapi.dev",
      "description": "Staging API"
    }
  ],
  "tags": [
    {
      "name": "System",
      "description": "System health and operational endpoints"
    },
    {
      "name": "User",
      "description": "User balance and account information"
    },
    {
      "name": "Jobs",
      "description": "Billable job execution engine"
    },
    {
      "name": "Reddit",
      "description": "Reddit posts, comment trees, subreddit listings and search"
    },
    {
      "name": "Monitors",
      "description": "Keyword monitors across Reddit posts and comments with webhook delivery"
    }
  ],
  "paths": {
    "/api/v1/health": {
      "get": {
        "summary": "Health check",
        "x-pricing": "Free (0 credits)",
        "x-permission": "public",
        "description": "Returns service health status, version, commit, and build time.",
        "operationId": "getHealth",
        "tags": [
          "System"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Service is healthy",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/user/balance": {
      "get": {
        "summary": "Get user credit balance",
        "x-pricing": "Free (0 credits)",
        "x-permission": "user:read",
        "description": "Returns the authenticated user's ID and current credit balance.",
        "operationId": "getUserBalance",
        "tags": [
          "User"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Current user balance",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/v1/jobs/execute": {
      "post": {
        "summary": "Execute job",
        "x-pricing": "Dynamic based on action",
        "x-permission": "jobs:write",
        "description": "Runs a billable job by action name and parameters, deducting credits accordingly.",
        "operationId": "executeJob",
        "tags": [
          "Jobs"
        ],
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JobRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Job executed successfully",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/v1/reddit/post": {
      "get": {
        "operationId": "getPost",
        "tags": [
          "Reddit"
        ],
        "summary": "Read Post",
        "x-pricing": "1 credit up to 500 comments (+1 per further 100)",
        "x-permission": "reddit:read",
        "description": "Returns a Reddit post with its nested comment tree and synthesized discussion digest, formatted as JSON, Markdown, or a graph.\n\nReddit hides long threads behind \"load more comments\"; threadapi automatically follows those links until it has collected the requested comments. The digest highlights OP follow-up replies, top-upvoted comments, and controversial discussions.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "description": "Reddit post URL (any reddit.com, redd.it, or share link) or post ID. Either `url` or `id` is required.",
            "schema": {
              "type": "string"
            },
            "example": "https://www.reddit.com/r/programming/comments/1x144ok/how_big_is_a_git_commit/"
          },
          {
            "name": "id",
            "in": "query",
            "description": "Post ID (e.g. `1x144ok`) or `t3_` fullname. Alternative to `url`.",
            "schema": {
              "type": "string"
            },
            "example": "1x144ok"
          },
          {
            "name": "comment",
            "in": "query",
            "description": "Comment ID to focus on. When set, returns its parent ancestor chain and direct replies.",
            "schema": {
              "type": "string"
            },
            "example": "pezplxi"
          },
          {
            "name": "context",
            "in": "query",
            "description": "Number of ancestor context levels to include above the focused comment.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 8,
              "default": 3
            }
          },
          {
            "name": "max_comments",
            "in": "query",
            "description": "Maximum comments to return. Set to `0` to return the post alone.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 2000,
              "default": 200
            }
          },
          {
            "name": "format",
            "in": "query",
            "description": "Response format: `json` (complete post and digest), `md` (Markdown for LLMs), or `graph` (discussion digest only).",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "md",
                "graph"
              ],
              "default": "json"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The post.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              },
              "X-Comments-Returned": {
                "description": "Comments in the response.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-Has-More": {
                "description": "Whether a larger `max_comments` would return more comments.",
                "schema": {
                  "type": "boolean"
                }
              },
              "X-Cache-Tier": {
                "description": "Where the post came from. `MISS` and `PARTIAL` mean some of it was fetched from Reddit now.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "L1_TINYLFU",
                    "L2_DISK",
                    "PARTIAL",
                    "MISS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostResponse"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "403": {
            "$ref": "#/components/responses/RedditRefused"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/v1/reddit/post/duplicates": {
      "get": {
        "operationId": "getPostDuplicates",
        "tags": [
          "Reddit"
        ],
        "summary": "Get Duplicate Posts",
        "x-pricing": "1 credit per request",
        "x-permission": "reddit:read",
        "description": "Retrieves other discussions and crossposts sharing the same external URL across Reddit.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "description": "Reddit post ID (e.g. `1x1ai6v` or `t3_1x1ai6v`). Required if `url` is not provided.",
            "schema": {
              "type": "string"
            },
            "example": "1x1ai6v"
          },
          {
            "name": "url",
            "in": "query",
            "description": "Reddit post URL. Required if `id` is not provided.",
            "schema": {
              "type": "string"
            },
            "example": "https://www.reddit.com/r/SaaS/comments/1x1ai6v/slug/"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/After"
          },
          {
            "$ref": "#/components/parameters/NSFW"
          }
        ],
        "responses": {
          "200": {
            "description": "Duplicate posts.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              },
              "X-Cache-Tier": {
                "description": "Where the listing came from (`L1_LISTING` or `MISS`).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "L1_LISTING",
                    "MISS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Listing"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "403": {
            "$ref": "#/components/responses/RedditRefused"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/v1/reddit/things": {
      "get": {
        "operationId": "getThings",
        "tags": [
          "Reddit"
        ],
        "summary": "Look Up Posts by ID",
        "x-pricing": "1 credit per request",
        "x-permission": "reddit:read",
        "description": "Batch look up up to 100 Reddit posts by fullname (`t3_`), bare ID, or URL in requested order. Any missing IDs are recorded under `missing_ids`.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "ids",
            "in": "query",
            "required": true,
            "description": "Comma-separated list of up to 100 Reddit post IDs or URLs.",
            "schema": {
              "type": "string"
            },
            "example": "t3_1x1ai6v,t3_1xagllz"
          }
        ],
        "responses": {
          "200": {
            "description": "The requested items.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              },
              "X-Cache-Tier": {
                "description": "Cache tier (`MISS`).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "MISS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThingsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/v1/reddit/by_id": {
      "get": {
        "operationId": "getPostsByID",
        "tags": [
          "Reddit"
        ],
        "summary": "Look Up Posts by ID (Official)",
        "x-pricing": "1 credit per request",
        "x-permission": "reddit:read",
        "description": "Batch look up up to 100 posts via Reddit's official `/by_id/` endpoint.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "ids",
            "in": "query",
            "required": true,
            "description": "Comma-separated list of up to 100 Reddit post IDs or URLs.",
            "schema": {
              "type": "string"
            },
            "example": "t3_1x1ai6v,t3_1wuyulc"
          }
        ],
        "responses": {
          "200": {
            "description": "The requested posts.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              },
              "X-Cache-Tier": {
                "description": "Cache tier (`MISS`).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "MISS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThingsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/v1/reddit/posts/by_id": {
      "get": {
        "operationId": "getPostsByIDAlias",
        "tags": [
          "Reddit"
        ],
        "summary": "Look Up Posts by ID (Alias)",
        "x-pricing": "1 credit per request",
        "x-permission": "reddit:read",
        "description": "Alias for `/v1/reddit/by_id`. Looks up to 100 posts by fullname (`t3_`), bare ID, or URL.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "ids",
            "in": "query",
            "required": true,
            "description": "Comma-separated list of up to 100 Reddit post IDs or URLs.",
            "schema": {
              "type": "string"
            },
            "example": "t3_1x1ai6v,t3_1wuyulc"
          }
        ],
        "responses": {
          "200": {
            "description": "The requested posts.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              },
              "X-Cache-Tier": {
                "description": "Cache tier (`MISS`).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "MISS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThingsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/v1/reddit/subreddit": {
      "get": {
        "operationId": "listSubreddit",
        "tags": [
          "Reddit"
        ],
        "summary": "List Subreddit Posts",
        "x-pricing": "1 credit per page",
        "x-permission": "reddit:read",
        "description": "Lists posts from a subreddit sorted by community filters (`hot`, `new`, `top`, `rising`, `controversial`). Returns up to 100 posts per page.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "sub",
            "in": "query",
            "required": true,
            "description": "Subreddit name, with or without `r/`.",
            "schema": {
              "type": "string"
            },
            "example": "golang"
          },
          {
            "$ref": "#/components/parameters/SubredditSort"
          },
          {
            "$ref": "#/components/parameters/Time"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/After"
          },
          {
            "$ref": "#/components/parameters/NSFW"
          }
        ],
        "responses": {
          "200": {
            "description": "The posts.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              },
              "X-Cache-Tier": {
                "description": "Where the listing came from (`L1_LISTING` or `MISS`).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "L1_LISTING",
                    "MISS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Listing"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "403": {
            "$ref": "#/components/responses/RedditRefused"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/v1/reddit/subreddit/about": {
      "get": {
        "operationId": "getSubredditAbout",
        "tags": [
          "Reddit"
        ],
        "summary": "Get Subreddit Details",
        "x-pricing": "1 credit per request",
        "x-permission": "reddit:read",
        "description": "Retrieves subreddit metadata, community settings, subscriber stats, and moderation rules.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "sub",
            "in": "query",
            "required": true,
            "description": "Subreddit name, with or without `r/`.",
            "schema": {
              "type": "string"
            },
            "example": "golang"
          }
        ],
        "responses": {
          "200": {
            "description": "Subreddit metadata and rules.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              },
              "X-Cache-Tier": {
                "description": "Where the data came from (`L1_LISTING` or `MISS`).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "L1_LISTING",
                    "MISS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subreddit"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "403": {
            "$ref": "#/components/responses/RedditRefused"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/v1/reddit/subreddit/comments": {
      "get": {
        "operationId": "getSubredditComments",
        "tags": [
          "Reddit"
        ],
        "summary": "List Subreddit Comments",
        "x-pricing": "1 credit per page",
        "x-permission": "reddit:read",
        "description": "Fetches recent comments posted across an entire subreddit in reverse chronological order.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "sub",
            "in": "query",
            "required": true,
            "description": "Subreddit name (e.g. `golang` or `r/golang`).",
            "schema": {
              "type": "string"
            },
            "example": "golang"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/After"
          },
          {
            "$ref": "#/components/parameters/NSFW"
          }
        ],
        "responses": {
          "200": {
            "description": "Subreddit comments.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              },
              "X-Cache-Tier": {
                "description": "Where the listing came from (`L1_LISTING` or `MISS`).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "L1_LISTING",
                    "MISS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommentListing"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/v1/reddit/subreddits": {
      "get": {
        "operationId": "getSubreddits",
        "tags": [
          "Reddit"
        ],
        "summary": "List Subreddits",
        "x-pricing": "1 credit per page",
        "x-permission": "reddit:read",
        "description": "Lists popular or newly created subreddits across Reddit.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "sort",
            "in": "query",
            "description": "Subreddit listing sort.",
            "schema": {
              "type": "string",
              "enum": [
                "popular",
                "new"
              ],
              "default": "popular"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/After"
          },
          {
            "$ref": "#/components/parameters/NSFW"
          }
        ],
        "responses": {
          "200": {
            "description": "Subreddit listing.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              },
              "X-Cache-Tier": {
                "description": "Where the listing came from (`L1_LISTING` or `MISS`).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "L1_LISTING",
                    "MISS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubredditListing"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/v1/reddit/user": {
      "get": {
        "operationId": "getUser",
        "tags": [
          "Reddit"
        ],
        "summary": "Get User Profile",
        "x-pricing": "1 credit per request",
        "x-permission": "reddit:read",
        "description": "Retrieves a Reddit user's public profile, karma breakdown, creation timestamp, and account flags.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": true,
            "description": "Reddit username (e.g. `spez`, with or without `u/`).",
            "schema": {
              "type": "string"
            },
            "example": "spez"
          }
        ],
        "responses": {
          "200": {
            "description": "User profile.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              },
              "X-Cache-Tier": {
                "description": "Where the data came from (`L1_LISTING` or `MISS`).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "L1_LISTING",
                    "MISS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/v1/reddit/user/posts": {
      "get": {
        "operationId": "getUserPosts",
        "tags": [
          "Reddit"
        ],
        "summary": "List User Posts",
        "x-pricing": "1 credit per page",
        "x-permission": "reddit:read",
        "description": "Lists submissions posted by a specific Reddit user across all communities.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": true,
            "description": "Reddit username.",
            "schema": {
              "type": "string"
            },
            "example": "spez"
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "new",
                "hot",
                "top",
                "controversial"
              ],
              "default": "new"
            }
          },
          {
            "$ref": "#/components/parameters/Time"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/After"
          },
          {
            "$ref": "#/components/parameters/NSFW"
          }
        ],
        "responses": {
          "200": {
            "description": "Submitted posts.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              },
              "X-Cache-Tier": {
                "description": "Where the listing came from (`L1_LISTING` or `MISS`).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "L1_LISTING",
                    "MISS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Listing"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/v1/reddit/user/comments": {
      "get": {
        "operationId": "getUserComments",
        "tags": [
          "Reddit"
        ],
        "summary": "List User Comments",
        "x-pricing": "1 credit per page",
        "x-permission": "reddit:read",
        "description": "Lists comments posted by a specific Reddit user across all communities.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": true,
            "description": "Reddit username.",
            "schema": {
              "type": "string"
            },
            "example": "spez"
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "new",
                "hot",
                "top",
                "controversial"
              ],
              "default": "new"
            }
          },
          {
            "$ref": "#/components/parameters/Time"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/After"
          },
          {
            "$ref": "#/components/parameters/NSFW"
          }
        ],
        "responses": {
          "200": {
            "description": "Submitted comments.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              },
              "X-Cache-Tier": {
                "description": "Where the listing came from (`L1_LISTING` or `MISS`).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "L1_LISTING",
                    "MISS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommentListing"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/v1/reddit/search": {
      "get": {
        "operationId": "search",
        "tags": [
          "Reddit"
        ],
        "summary": "Search Reddit Posts",
        "x-pricing": "1 credit per page",
        "x-permission": "reddit:read",
        "description": "Searches Reddit posts, subreddits, or users matching a query string globally or within a specified subreddit.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Search query, 1 to 256 characters.",
            "schema": {
              "type": "string",
              "maxLength": 256
            },
            "example": "best crm for small agency"
          },
          {
            "name": "type",
            "in": "query",
            "description": "Content type to search: post, subreddit, or user.",
            "schema": {
              "type": "string",
              "enum": [
                "post",
                "subreddit",
                "user"
              ],
              "default": "post"
            }
          },
          {
            "name": "sub",
            "in": "query",
            "description": "Only search this subreddit.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "relevance",
                "new",
                "top",
                "comments"
              ],
              "default": "relevance"
            }
          },
          {
            "$ref": "#/components/parameters/Time"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/After"
          },
          {
            "$ref": "#/components/parameters/NSFW"
          }
        ],
        "responses": {
          "200": {
            "description": "The search results.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              },
              "X-Cache-Tier": {
                "description": "Where the search results came from (`L1_LISTING` or `MISS`).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "L1_LISTING",
                    "MISS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Listing"
                    },
                    {
                      "$ref": "#/components/schemas/SubredditListing"
                    },
                    {
                      "$ref": "#/components/schemas/UserListing"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/v1/reddit/search/comments": {
      "get": {
        "operationId": "searchComments",
        "tags": [
          "Reddit"
        ],
        "summary": "Search Reddit Comments",
        "x-pricing": "1 credit per page",
        "x-permission": "reddit:read",
        "description": "Searches Reddit comments globally or scoped to a specific subreddit with pagination support.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Search query, 1 to 500 characters.",
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "example": "postgres replica lag"
          },
          {
            "name": "sub",
            "in": "query",
            "description": "Only search this subreddit.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "relevance",
                "new",
                "top"
              ],
              "default": "relevance"
            }
          },
          {
            "$ref": "#/components/parameters/Time"
          },
          {
            "$ref": "#/components/parameters/After"
          },
          {
            "$ref": "#/components/parameters/NSFW"
          }
        ],
        "responses": {
          "200": {
            "description": "The comments.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              },
              "X-Cache-Tier": {
                "description": "Cache tier (`MISS`).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "MISS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommentListing"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "403": {
            "$ref": "#/components/responses/RedditRefused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/v1/reddit/search/comments/direct": {
      "get": {
        "operationId": "searchCommentsDirect",
        "tags": [
          "Reddit"
        ],
        "summary": "Search Comments (Direct)",
        "x-pricing": "1 credit per page",
        "x-permission": "reddit:read",
        "description": "High-speed comment search extracting directly from Shreddit DOM markup, bypassing secondary upstream calls.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Search query, 1 to 500 characters.",
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "example": "postgres replica lag"
          },
          {
            "name": "sub",
            "in": "query",
            "description": "Only search this subreddit.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "relevance",
                "new",
                "top"
              ],
              "default": "relevance"
            }
          },
          {
            "$ref": "#/components/parameters/Time"
          },
          {
            "$ref": "#/components/parameters/After"
          },
          {
            "$ref": "#/components/parameters/NSFW"
          }
        ],
        "responses": {
          "200": {
            "description": "The comments.",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              },
              "X-Cache-Tier": {
                "description": "Cache tier (`MISS`).",
                "schema": {
                  "type": "string",
                  "enum": [
                    "MISS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommentListing"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "403": {
            "$ref": "#/components/responses/RedditRefused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/v1/monitors": {
      "post": {
        "operationId": "createMonitor",
        "tags": [
          "Monitors"
        ],
        "summary": "Create Monitor",
        "x-pricing": "10 credits / 24h",
        "x-permission": "monitors:write",
        "description": "Creates a new keyword monitor across Reddit posts and/or comments. Billed 10 credits upfront for the first 24 hours. Daily match volume and webhooks are free.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "keywords"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "example": "Mentions of restic"
                  },
                  "keywords": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "example": [
                      "restic",
                      "\"borg backup\""
                    ]
                  },
                  "exclude": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "example": [
                      "hiring"
                    ]
                  },
                  "subreddits": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "example": [
                      "selfhosted",
                      "DataHoarder"
                    ]
                  },
                  "posts": {
                    "type": "boolean",
                    "default": true
                  },
                  "comments": {
                    "type": "boolean",
                    "default": true
                  },
                  "nsfw": {
                    "type": "boolean",
                    "default": false
                  },
                  "webhook_url": {
                    "type": "string",
                    "example": "https://example.com/hook"
                  },
                  "webhook_kind": {
                    "type": "string",
                    "enum": [
                      "generic",
                      "slack",
                      "discord",
                      "telegram"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created monitor and HMAC secret",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "monitor": {
                      "$ref": "#/components/schemas/Monitor"
                    },
                    "webhook_secret": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "get": {
        "operationId": "listMonitors",
        "tags": [
          "Monitors"
        ],
        "summary": "List Monitors",
        "x-pricing": "Free (0 credits)",
        "x-permission": "monitors:read",
        "description": "Returns all monitors configured by the authenticated user.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "List of monitors",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Monitor"
                      }
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "used": {
                      "type": "integer"
                    },
                    "daily_match_cap": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/monitors/{id}": {
      "get": {
        "operationId": "getMonitor",
        "tags": [
          "Monitors"
        ],
        "summary": "Get Monitor",
        "x-pricing": "Free (0 credits)",
        "x-permission": "monitors:read",
        "description": "Returns monitor configuration and 24-hour/7-day delivery and match statistics.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Monitor with statistics",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "monitor": {
                      "$ref": "#/components/schemas/Monitor"
                    },
                    "stats": {
                      "$ref": "#/components/schemas/MonitorStats"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "operationId": "updateMonitor",
        "tags": [
          "Monitors"
        ],
        "summary": "Update Monitor",
        "x-pricing": "Free (0 credits)",
        "x-permission": "monitors:write",
        "description": "Updates monitor settings. Changing the webhook URL clears any webhook_failing status.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "keywords": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "exclude": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "subreddits": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "posts": {
                    "type": "boolean"
                  },
                  "comments": {
                    "type": "boolean"
                  },
                  "nsfw": {
                    "type": "boolean"
                  },
                  "webhook_url": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "webhook_kind": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "generic",
                      "slack",
                      "discord",
                      "telegram",
                      null
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated monitor",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "monitor": {
                      "$ref": "#/components/schemas/Monitor"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteMonitor",
        "tags": [
          "Monitors"
        ],
        "summary": "Delete Monitor",
        "x-pricing": "Free (0 credits)",
        "x-permission": "monitors:write",
        "description": "Soft-deletes a monitor. Charging stops immediately.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Monitor deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "deleted"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/monitors/{id}/pause": {
      "post": {
        "operationId": "pauseMonitor",
        "tags": [
          "Monitors"
        ],
        "summary": "Pause Monitor",
        "x-pricing": "Free (0 credits)",
        "x-permission": "monitors:write",
        "description": "Pauses a monitor, halting match tracking and daily charges.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Monitor paused",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "paused"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/monitors/{id}/resume": {
      "post": {
        "operationId": "resumeMonitor",
        "tags": [
          "Monitors"
        ],
        "summary": "Resume Monitor",
        "x-pricing": "10 credits / 24h",
        "x-permission": "monitors:write",
        "description": "Resumes a paused monitor. Immediately charges 10 credits for the next 24 hours.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Resumed monitor",
            "headers": {
              "X-Credits-Used": {
                "$ref": "#/components/headers/CreditsUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "monitor": {
                      "$ref": "#/components/schemas/Monitor"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/OutOfCredits"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/monitors/{id}/rotate-secret": {
      "post": {
        "operationId": "rotateMonitorSecret",
        "tags": [
          "Monitors"
        ],
        "summary": "Rotate Webhook Secret",
        "x-pricing": "Free (0 credits)",
        "x-permission": "monitors:write",
        "description": "Generates and returns a new HMAC secret for generic webhooks.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "New secret",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhook_secret": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/monitors/{id}/test": {
      "post": {
        "operationId": "testMonitor",
        "tags": [
          "Monitors"
        ],
        "summary": "Test Webhook Delivery",
        "x-pricing": "Free (0 credits)",
        "x-permission": "monitors:write",
        "description": "Sends a sample test match to the configured webhook URL. Rate limited to 5 per minute.",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Test delivery outcome",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "delivered": {
                      "type": "boolean"
                    },
                    "status": {
                      "type": "integer"
                    },
                    "error": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/monitors/{id}/matches": {
      "get": {
        "operationId": "getMonitorMatches",
        "tags": [
          "Monitors"
        ],
        "summary": "Get Monitor Matches",
        "x-pricing": "Free (0 credits)",
        "x-permission": "monitors:read",
        "description": "Returns matches collected by the monitor. Supports streaming pagination via `after`, or reverse chronological sorting with `order=newest`.\n",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "order",
            "in": "query",
            "description": "Sort ordering for returned matches.",
            "schema": {
              "type": "string",
              "enum": [
                "oldest",
                "newest"
              ],
              "default": "oldest"
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "With `order=oldest`, cursor for the next page of matches.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "before",
            "in": "query",
            "description": "With `order=newest`, cursor for the next page of matches.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum items to return.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of matches",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MonitorMatch"
                      }
                    },
                    "after": {
                      "type": "string",
                      "description": "With `order=oldest`, the cursor for the next page when one is waiting."
                    },
                    "before": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key or OAuth 2.1 access token"
      },
      "apiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "API key"
      }
    },
    "headers": {
      "RequestId": {
        "description": "Unique identifier generated by the server for tracing and idempotency.",
        "schema": {
          "type": "string",
          "example": "req_0123456789abcdef0123456789abcdef"
        }
      },
      "RateLimitLimit": {
        "description": "Configured request rate limit for the client's current tier.",
        "schema": {
          "type": "integer",
          "example": 100
        }
      },
      "RateLimitRemaining": {
        "description": "Number of requests remaining in the current rate limit window.",
        "schema": {
          "type": "integer",
          "example": 99
        }
      },
      "RetryAfter": {
        "description": "Number of seconds to wait before retrying after rate limit exhaustion.",
        "schema": {
          "type": "integer",
          "example": 60
        }
      },
      "CreditsUsed": {
        "description": "Credits this request cost.",
        "schema": {
          "type": "integer",
          "example": 1
        }
      }
    },
    "parameters": {
      "SubredditSort": {
        "name": "sort",
        "in": "query",
        "schema": {
          "type": "string",
          "enum": [
            "hot",
            "new",
            "top",
            "rising",
            "controversial"
          ],
          "default": "hot"
        }
      },
      "Time": {
        "name": "t",
        "in": "query",
        "description": "Time window when sorting by `top` or `controversial`.",
        "schema": {
          "type": "string",
          "enum": [
            "hour",
            "day",
            "week",
            "month",
            "year",
            "all"
          ]
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "description": "Number of items per page.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        }
      },
      "After": {
        "name": "after",
        "in": "query",
        "description": "Pagination cursor from the previous page's `after` field.",
        "schema": {
          "type": "string"
        }
      },
      "NSFW": {
        "name": "nsfw",
        "in": "query",
        "description": "Include NSFW content (filtered out by default).",
        "schema": {
          "type": "boolean",
          "default": false
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Bad request (invalid parameter or unknown action)",
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                {
                  "$ref": "#/components/schemas/Error"
                }
              ]
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key or OAuth access token",
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                {
                  "$ref": "#/components/schemas/Error"
                }
              ]
            }
          }
        }
      },
      "PaymentRequired": {
        "description": "Insufficient credit balance to execute the requested job",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "OutOfCredits": {
        "description": "The account has no credits left (`insufficient_credits`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RedditRefused": {
        "description": "Reddit does not show this content to logged-out readers, e.g. a private or quarantined subreddit (`reddit_refused`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unavailable": {
        "description": "A temporary problem reaching Reddit (`upstream_busy`, `upstream_timeout`, `upstream_error`). Retry shortly; nothing was billed.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Insufficient permissions or scope for this endpoint",
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                {
                  "$ref": "#/components/schemas/Error"
                }
              ]
            }
          }
        }
      },
      "NotFound": {
        "description": "Requested user or resource not found",
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                {
                  "$ref": "#/components/schemas/Error"
                }
              ]
            }
          }
        }
      },
      "Conflict": {
        "description": "Conflict (e.g. duplicate transaction or idempotent request collision)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit or daily request quota exceeded",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                {
                  "$ref": "#/components/schemas/Error"
                }
              ]
            }
          }
        }
      },
      "InternalServerError": {
        "description": "Internal server error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    },
    "schemas": {
      "HealthResponse": {
        "type": "object",
        "required": [
          "status",
          "service",
          "timestamp",
          "version",
          "commit",
          "build_time"
        ],
        "properties": {
          "status": {
            "type": "string",
            "example": "ok"
          },
          "service": {
            "type": "string",
            "example": "core-go"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "example": "2026-10-23T12:00:00Z"
          },
          "version": {
            "type": "string",
            "example": "dev"
          },
          "commit": {
            "type": "string",
            "example": "dev"
          },
          "build_time": {
            "type": "string",
            "example": "dev"
          }
        }
      },
      "BalanceResponse": {
        "type": "object",
        "required": [
          "user_id",
          "credit_balance"
        ],
        "properties": {
          "user_id": {
            "type": "string",
            "example": "usr_12345"
          },
          "credit_balance": {
            "type": "integer",
            "example": 100
          }
        }
      },
      "JobRequest": {
        "type": "object",
        "required": [
          "action"
        ],
        "properties": {
          "action": {
            "type": "string",
            "description": "Name of the job action to execute",
            "enum": [
              "transcribe_video_summary",
              "generate_embeddings_batch",
              "dispatch_webhook_event"
            ],
            "example": "generate_embeddings_batch"
          },
          "params": {
            "type": "object",
            "description": "Arbitrary parameters for the job action",
            "additionalProperties": true,
            "example": {}
          }
        }
      },
      "JobResponse": {
        "type": "object",
        "required": [
          "success",
          "action",
          "credits_deducted",
          "remaining_credits",
          "processed_at",
          "output"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "example": true
          },
          "action": {
            "type": "string",
            "example": "generate_embeddings_batch"
          },
          "credits_deducted": {
            "type": "integer",
            "example": 10
          },
          "remaining_credits": {
            "type": "integer",
            "example": 90
          },
          "processed_at": {
            "type": "string",
            "format": "date-time",
            "example": "2026-10-23T12:00:00Z"
          },
          "output": {
            "type": "string",
            "example": "Job completed successfully by core-go engine"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message",
            "example": "unauthorized: missing or invalid credentials"
          },
          "error_code": {
            "type": "string",
            "description": "Machine-readable error code. Known values include: forbidden_scope, rate_limited, daily_quota_exceeded, insufficient_credits, duplicate_transaction. Additional codes may be introduced in future releases.",
            "enum": [
              "forbidden_scope",
              "rate_limited",
              "daily_quota_exceeded",
              "insufficient_credits",
              "duplicate_transaction"
            ],
            "example": "insufficient_credits"
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "retryable"
            ],
            "properties": {
              "code": {
                "type": "string",
                "example": "not_found"
              },
              "message": {
                "type": "string"
              },
              "retryable": {
                "type": "boolean"
              },
              "retry_after": {
                "type": "integer",
                "description": "Seconds to wait before retrying."
              }
            }
          }
        }
      },
      "PostResponse": {
        "type": "object",
        "properties": {
          "post": {
            "$ref": "#/components/schemas/Post"
          },
          "discussion_graph": {
            "$ref": "#/components/schemas/DiscussionGraph"
          },
          "meta": {
            "$ref": "#/components/schemas/PostMeta"
          }
        }
      },
      "PostMeta": {
        "type": "object",
        "properties": {
          "comments_returned": {
            "type": "integer",
            "description": "Comments in the response."
          },
          "comments_total": {
            "type": "integer",
            "description": "Reddit's comment count, deleted and hidden comments included."
          },
          "has_more": {
            "type": "boolean",
            "description": "A larger max_comments would return more."
          },
          "max_comments": {
            "type": "integer"
          },
          "credits_used": {
            "type": "integer"
          },
          "cache": {
            "type": "string"
          },
          "limited_by_balance": {
            "type": "boolean"
          },
          "focus_comment_id": {
            "type": "string",
            "description": "Comment ID when a comment permalink was requested."
          }
        }
      },
      "Post": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "domain": {
            "type": "string"
          },
          "is_self": {
            "type": "boolean"
          },
          "flair": {
            "type": "string"
          },
          "spoiler": {
            "type": "boolean"
          },
          "stickied": {
            "type": "boolean"
          },
          "locked": {
            "type": "boolean"
          },
          "removed": {
            "type": "boolean"
          },
          "subreddit": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "author": {
            "type": "string"
          },
          "score": {
            "type": "integer"
          },
          "upvote_ratio": {
            "type": "number"
          },
          "num_comments": {
            "type": "integer"
          },
          "url": {
            "type": "string"
          },
          "permalink": {
            "type": "string"
          },
          "selftext": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "is_video": {
            "type": "boolean"
          },
          "over_18": {
            "type": "boolean"
          },
          "media": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "image",
                    "video",
                    "gallery"
                  ]
                },
                "url": {
                  "type": "string"
                },
                "width": {
                  "type": "integer"
                },
                "height": {
                  "type": "integer"
                },
                "caption": {
                  "type": "string"
                }
              }
            }
          },
          "poll": {
            "type": "object",
            "properties": {
              "total_votes": {
                "type": "integer"
              },
              "is_closed": {
                "type": "boolean"
              },
              "options": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "text": {
                      "type": "string"
                    },
                    "vote_count": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "crosspost_of": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "subreddit": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "author": {
                "type": "string"
              },
              "permalink": {
                "type": "string"
              }
            }
          },
          "comments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Comment"
            }
          }
        }
      },
      "Comment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "parent_id": {
            "type": "string",
            "description": "t3_<post id> for a top-level comment, t1_<comment id> for a reply."
          },
          "author": {
            "type": "string"
          },
          "score": {
            "type": "integer"
          },
          "body": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "depth": {
            "type": "integer"
          },
          "is_submitter": {
            "type": "boolean",
            "description": "Written by the original poster."
          },
          "controversy": {
            "type": "integer"
          },
          "replies": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Comment"
            }
          }
        }
      },
      "DiscussionGraph": {
        "type": "object",
        "properties": {
          "post_id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "author": {
            "type": "string"
          },
          "author_followups": {
            "type": "array",
            "description": "The original poster's own comments in the thread.",
            "items": {
              "$ref": "#/components/schemas/Comment"
            }
          },
          "most_upvoted": {
            "type": "array",
            "description": "Highest-score comments excluding OP, AutoModerator and deleted comments.",
            "items": {
              "$ref": "#/components/schemas/Comment"
            }
          },
          "controversial": {
            "type": "array",
            "description": "Comments with controversiality flag or negative score, excluding OP.",
            "items": {
              "$ref": "#/components/schemas/Comment"
            }
          },
          "total_analyzed": {
            "type": "integer"
          }
        }
      },
      "Listing": {
        "type": "object",
        "required": [
          "sort",
          "count",
          "items",
          "filtered_nsfw"
        ],
        "properties": {
          "subreddit": {
            "type": [
              "string",
              "null"
            ]
          },
          "query": {
            "type": [
              "string",
              "null"
            ]
          },
          "sort": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Post"
            }
          },
          "after": {
            "type": [
              "string",
              "null"
            ]
          },
          "filtered_nsfw": {
            "type": "integer"
          },
          "degraded": {
            "type": "boolean"
          }
        }
      },
      "ThingItem": {
        "type": "object",
        "required": [
          "kind"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "post",
              "comment"
            ]
          },
          "post": {
            "$ref": "#/components/schemas/Post"
          },
          "comment": {
            "$ref": "#/components/schemas/CommentItem"
          }
        }
      },
      "ThingsResponse": {
        "type": "object",
        "required": [
          "items",
          "missing"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ThingItem"
            }
          },
          "missing": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "CommentItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "post_id": {
            "type": "string"
          },
          "post_title": {
            "type": "string"
          },
          "subreddit": {
            "type": "string"
          },
          "author": {
            "type": "string"
          },
          "score": {
            "type": "integer"
          },
          "body": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "permalink": {
            "type": "string"
          },
          "parent_id": {
            "type": "string"
          },
          "is_submitter": {
            "type": "boolean"
          },
          "controversiality": {
            "type": "integer"
          }
        }
      },
      "SubredditRule": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string"
          },
          "short_name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "violation_reason": {
            "type": "string"
          },
          "priority": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Subreddit": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "public_description": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "subscribers": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "over_18": {
            "type": "boolean"
          },
          "type": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "icon": {
            "type": "string"
          },
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SubredditRule"
            }
          }
        }
      },
      "User": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "link_karma": {
            "type": "integer"
          },
          "comment_karma": {
            "type": "integer"
          },
          "total_karma": {
            "type": "integer"
          },
          "is_employee": {
            "type": "boolean"
          },
          "is_mod": {
            "type": "boolean"
          },
          "has_verified_email": {
            "type": "boolean"
          },
          "icon": {
            "type": "string"
          },
          "suspended": {
            "type": "boolean"
          }
        }
      },
      "CommentListing": {
        "type": "object",
        "required": [
          "sort",
          "count",
          "items",
          "filtered_nsfw"
        ],
        "properties": {
          "subreddit": {
            "type": [
              "string",
              "null"
            ]
          },
          "query": {
            "type": [
              "string",
              "null"
            ]
          },
          "sort": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CommentItem"
            }
          },
          "after": {
            "type": [
              "string",
              "null"
            ]
          },
          "filtered_nsfw": {
            "type": "integer"
          },
          "degraded": {
            "type": "boolean"
          }
        }
      },
      "SubredditListing": {
        "type": "object",
        "required": [
          "sort",
          "count",
          "items",
          "filtered_nsfw"
        ],
        "properties": {
          "query": {
            "type": [
              "string",
              "null"
            ]
          },
          "sort": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Subreddit"
            }
          },
          "after": {
            "type": [
              "string",
              "null"
            ]
          },
          "filtered_nsfw": {
            "type": "integer"
          },
          "degraded": {
            "type": "boolean"
          }
        }
      },
      "UserListing": {
        "type": "object",
        "required": [
          "sort",
          "count",
          "items",
          "filtered_nsfw"
        ],
        "properties": {
          "query": {
            "type": [
              "string",
              "null"
            ]
          },
          "sort": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/User"
            }
          },
          "after": {
            "type": [
              "string",
              "null"
            ]
          },
          "filtered_nsfw": {
            "type": "integer"
          },
          "degraded": {
            "type": "boolean"
          }
        }
      },
      "Monitor": {
        "type": "object",
        "required": [
          "id",
          "name",
          "keywords",
          "status",
          "include_posts",
          "include_comments",
          "nsfw",
          "next_charge_at",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "exclude": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "subreddits": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "include_posts": {
            "type": "boolean"
          },
          "include_comments": {
            "type": "boolean"
          },
          "nsfw": {
            "type": "boolean"
          },
          "webhook_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "webhook_kind": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "generic",
              "slack",
              "discord",
              "telegram",
              null
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused",
              "paused_balance",
              "deleted"
            ]
          },
          "webhook_failing": {
            "type": "boolean"
          },
          "next_charge_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_match_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "MonitorMatch": {
        "type": "object",
        "required": [
          "id",
          "monitor_id",
          "thing_id",
          "kind",
          "subreddit",
          "author",
          "title",
          "body",
          "permalink",
          "post_id",
          "created_utc",
          "matched_terms",
          "suppressed",
          "delivery_status",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "monitor_id": {
            "type": "string"
          },
          "thing_id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "post",
              "comment"
            ]
          },
          "subreddit": {
            "type": "string"
          },
          "author": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "permalink": {
            "type": "string"
          },
          "post_id": {
            "type": "string"
          },
          "created_utc": {
            "type": "string",
            "format": "date-time"
          },
          "matched_terms": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "suppressed": {
            "type": "boolean"
          },
          "delivery_status": {
            "type": "string",
            "enum": [
              "none",
              "pending",
              "delivered",
              "failed",
              "skipped"
            ]
          },
          "delivered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "MonitorStats": {
        "type": "object",
        "required": [
          "matches_today",
          "suppressed_today",
          "matches_7d",
          "delivery_failures_24h"
        ],
        "properties": {
          "matches_today": {
            "type": "integer"
          },
          "suppressed_today": {
            "type": "integer"
          },
          "matches_7d": {
            "type": "integer"
          },
          "last_match_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "delivery_failures_24h": {
            "type": "integer"
          }
        }
      }
    }
  }
}