{
  "openapi": "3.1.0",
  "info": {
    "title": "RedNest API",
    "version": "1.0.0",
    "description": "Everything the RedNest dashboard does, for agents. Connect with the device flow or OAuth (https://rednest.tech/docs/agents), then send `Authorization: Bearer <key>`. The same operations are MCP tools at https://rednest.tech/api/mcp."
  },
  "servers": [
    {
      "url": "https://rednest.tech"
    }
  ],
  "security": [
    {
      "bearer": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key (sck_…) or OAuth access token (sca_…)."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "error"
        ]
      }
    }
  },
  "paths": {
    "/api/v1/me": {
      "get": {
        "operationId": "get_me",
        "summary": "Who am I, and what's next",
        "description": "Start here. Returns the person this agent acts as, the GitHub accounts RedNest is installed on, scan access (lifetime free scan, wallet, $RED holder state), and `next_steps`: what is left to set up or do, in order (install the GitHub App, run a free scan, connect a wallet after launch, fix open findings). Steps only a person can take come with a URL to give them.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/keys": {
      "get": {
        "operationId": "list_api_keys",
        "summary": "List API keys and connected agents",
        "description": "Lists the person's API keys and the MCP clients they've connected, with when each was last used. Secrets are never shown again after they're created.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "create_api_key",
        "summary": "Create an API key",
        "description": "Creates an API key that acts as this person, for another agent, a CI job or a script. The key is returned once: store it (e.g. as SANDCHEST_API_KEY) and send it as `Authorization: Bearer <key>`.",
        "parameters": [],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "description": "What the key is for, e.g. \"CI\". Shown in Settings.",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/keys/{id}": {
      "delete": {
        "operationId": "revoke_api_key",
        "summary": "Revoke an API key",
        "description": "Revokes an API key, or disconnects an MCP client, by its id from list_api_keys. Use id \"current\" to revoke the key this request is using (signing the agent out).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The key's id, or \"current\".",
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "const": "current"
                },
                {
                  "type": "string",
                  "format": "uuid"
                }
              ],
              "description": "The key's id, or \"current\"."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/accounts": {
      "get": {
        "operationId": "list_accounts",
        "summary": "List accounts",
        "description": "Lists the GitHub accounts (personal or organization) RedNest is installed on that the person can see, with their plan, credits and repositories. Pass refresh=true after the person changes the App's repositories, or wait=50 while they install it: the call returns as soon as the new account shows.",
        "parameters": [
          {
            "name": "refresh",
            "in": "query",
            "required": false,
            "description": "Read the person's access from GitHub again first (takes a second or two).",
            "schema": {
              "description": "Read the person's access from GitHub again first (takes a second or two).",
              "type": "boolean"
            }
          },
          {
            "name": "wait",
            "in": "query",
            "required": false,
            "description": "Seconds to wait for a new account to appear while the person installs the GitHub App (re-reading GitHub every few seconds). Implies refresh.",
            "schema": {
              "description": "Seconds to wait for a new account to appear while the person installs the GitHub App (re-reading GitHub every few seconds). Implies refresh.",
              "type": "integer",
              "minimum": 0,
              "maximum": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/accounts/{account}": {
      "get": {
        "operationId": "get_account",
        "summary": "Get an account",
        "description": "One account's settings (Check threshold, emails, company details, first target), its hacker and its repositories.",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "required": true,
            "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login.",
            "schema": {
              "type": "string",
              "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "update_account",
        "summary": "Change an account's settings",
        "description": "Changes an account's settings (admins only). check_threshold: the lowest severity that fails the RedNest Check on pull requests. email_notifications: email people with access about critical findings and finished deep scans. company: name and billing email for receipts. first_target: the repository to deep scan first once the account joins the plan.",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "required": true,
            "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login.",
            "schema": {
              "type": "string",
              "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login."
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "check_threshold": {
                    "type": "string",
                    "enum": [
                      "critical",
                      "high",
                      "medium",
                      "low"
                    ]
                  },
                  "email_notifications": {
                    "type": "boolean"
                  },
                  "company": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "email": {
                        "anyOf": [
                          {
                            "type": "string",
                            "const": ""
                          },
                          {
                            "type": "string",
                            "format": "email"
                          }
                        ]
                      }
                    },
                    "required": [
                      "name",
                      "email"
                    ]
                  },
                  "first_target": {
                    "type": "string",
                    "description": "The repository: its id, or its full name as `owner/name`."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/accounts/{account}/hacker": {
      "patch": {
        "operationId": "update_hacker",
        "summary": "Recruit or restyle the hacker",
        "description": "Sets how the account's hacker looks and talks in the dashboard (admins only); scans are the same whatever you pick. Only the fields given change; an account that never recruited one starts from the defaults. handle: 1-16 letters, numbers, spaces, dots or dashes.",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "required": true,
            "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login.",
            "schema": {
              "type": "string",
              "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login."
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "handle": {
                    "type": "string"
                  },
                  "hoodie": {
                    "type": "string",
                    "enum": [
                      "charcoal",
                      "olive",
                      "oxblood",
                      "dune",
                      "midnight"
                    ]
                  },
                  "shell": {
                    "type": "string",
                    "enum": [
                      "obsidian",
                      "gunmetal",
                      "desert",
                      "scarred"
                    ]
                  },
                  "phosphor": {
                    "type": "string",
                    "enum": [
                      "amber",
                      "green",
                      "cyan",
                      "red",
                      "ice"
                    ]
                  },
                  "room": {
                    "type": "string",
                    "enum": [
                      "bunker",
                      "neon",
                      "server"
                    ]
                  },
                  "stickers": {
                    "maxItems": 4,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "skull",
                        "chest",
                        "duck",
                        "zeroday",
                        "padlock",
                        "sudo",
                        "hazard",
                        "bug",
                        "coffee",
                        "cat"
                      ]
                    }
                  },
                  "voice": {
                    "type": "string",
                    "enum": [
                      "terse",
                      "dry",
                      "paranoid",
                      "showman"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/accounts/{account}/billing": {
      "get": {
        "operationId": "get_billing",
        "summary": "Get billing",
        "description": "An account's plan, credits, auto top-up, whether a card is on file, free credits it can claim, and the price list (credits per deep scan and PR review). Read live from billing, so call it after the person pays to see the plan take effect.",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "required": true,
            "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login.",
            "schema": {
              "type": "string",
              "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login."
            }
          },
          {
            "name": "wait",
            "in": "query",
            "required": false,
            "description": "Seconds to wait for a paid plan to take effect while the person pays on Stripe (re-reading billing every few seconds).",
            "schema": {
              "description": "Seconds to wait for a paid plan to take effect while the person pays on Stripe (re-reading billing every few seconds).",
              "type": "integer",
              "minimum": 0,
              "maximum": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/accounts/{account}/billing/quote": {
      "post": {
        "operationId": "quote_credits",
        "summary": "Price a credit purchase",
        "description": "Prices buying credits for an account without charging anything: what's due now (with any promotion code), and whether it would charge the card on file or need the person to pay on Stripe Checkout. Admins only.",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "required": true,
            "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login.",
            "schema": {
              "type": "string",
              "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login."
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "credits": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 1000,
                    "description": "How many credits to buy (1-1000). Credits are $1 each, less in bigger purchases."
                  },
                  "promotion_code": {
                    "type": "string",
                    "description": "A promotion code, if the person has one. A free-credit code claims free credits instead of charging."
                  }
                },
                "required": [
                  "credits"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/accounts/{account}/billing/purchase": {
      "post": {
        "operationId": "buy_credits",
        "summary": "Buy credits",
        "description": "Buys credits for an account (admins only). With a card on file it charges it at once and returns the new balance. Without one (no plan yet, or on free credits), it joins the plan with these credits and returns `checkout_url`: give it to the person to pay on Stripe, then call get_billing with wait=50 until the plan shows. A card that needs an extra check (3-D Secure) also returns a URL for the person. Pass max_usd to refuse anything dearer than you expect.",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "required": true,
            "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login.",
            "schema": {
              "type": "string",
              "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login."
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "credits": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 1000,
                    "description": "How many credits to buy (1-1000). Credits are $1 each, less in bigger purchases."
                  },
                  "promotion_code": {
                    "type": "string",
                    "description": "A promotion code, if the person has one. A free-credit code claims free credits instead of charging."
                  },
                  "max_usd": {
                    "description": "Refuse (charging nothing) if this purchase would cost more than this many USD.",
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 100000
                  },
                  "auto_top_up": {
                    "description": "On a first purchase: also buy this many credits again automatically whenever fewer than 5 are left (up to a monthly limit).",
                    "type": "boolean"
                  }
                },
                "required": [
                  "credits"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/accounts/{account}/billing/claim": {
      "post": {
        "operationId": "claim_free_credits",
        "summary": "Claim free credits",
        "description": "Claims 20 free credits for an account, with no card (admins only). Once per GitHub account and once per person, for accounts that have never had a plan, while the offer lasts. Starts mapping the account's repositories straight away.",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "required": true,
            "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login.",
            "schema": {
              "type": "string",
              "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login."
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "code": {
                    "description": "A free-credit code, if the person was given one.",
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/accounts/{account}/billing/auto-top-up": {
      "put": {
        "operationId": "set_auto_top_up",
        "summary": "Set auto top-up",
        "description": "Turns auto top-up on or off for an account on a paid plan (admins only): when fewer than 5 credits are left, buy `credits` more on the card on file, spending at most monthly_limit_usd a month.",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "required": true,
            "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login.",
            "schema": {
              "type": "string",
              "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login."
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  },
                  "credits": {
                    "description": "How many credits each top-up buys. Default: the last choice, else 10.",
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 1000
                  },
                  "monthly_limit_usd": {
                    "description": "The most auto top-up may spend in a month. Default: five top-ups' worth, at least $50.",
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100000
                  }
                },
                "required": [
                  "enabled"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/accounts/{account}/billing/portal": {
      "post": {
        "operationId": "open_billing_portal",
        "summary": "Billing portal link",
        "description": "A link to Stripe's billing portal for an account (admins only), for the person to change the card, download invoices or cancel. The link is short-lived: give it to the person straight away.",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "required": true,
            "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login.",
            "schema": {
              "type": "string",
              "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/accounts/{account}/billing/invoice-details": {
      "put": {
        "operationId": "set_invoice_details",
        "summary": "Set invoice details",
        "description": "Sets the business name, address and optional tax ID (e.g. eu_vat, gb_vat, us_ein) shown on an account's invoices (admins only). Best done before the first purchase, so its invoice carries them.",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "required": true,
            "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login.",
            "schema": {
              "type": "string",
              "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login."
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "address": {
                    "type": "object",
                    "properties": {
                      "line1": {
                        "type": "string"
                      },
                      "line2": {
                        "anyOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "city": {
                        "type": "string"
                      },
                      "state": {
                        "anyOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "postal_code": {
                        "type": "string"
                      },
                      "country": {
                        "type": "string",
                        "description": "Two-letter country code, e.g. US, GB, DE."
                      }
                    },
                    "required": [
                      "line1",
                      "city",
                      "postal_code",
                      "country"
                    ]
                  },
                  "tax_id": {
                    "anyOf": [
                      {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "description": "Stripe's tax ID type, e.g. eu_vat, gb_vat, us_ein, au_abn."
                          },
                          "value": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "type",
                          "value"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "name",
                  "address"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/repos": {
      "get": {
        "operationId": "list_repos",
        "summary": "List repositories",
        "description": "Repositories RedNest can scan for this person (installed, with push access), most exposed first: open findings by severity, the latest scan, and what a deep scan costs now (or whether it's the account's free first one).",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "required": false,
            "description": "Only this account's repositories.",
            "schema": {
              "description": "Only this account's repositories.",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/repos/{repo}": {
      "get": {
        "operationId": "get_repo",
        "summary": "Get a repository",
        "description": "One repository: open findings, deep scan price, recent scans, and its threat model (what recon mapped: entry points, trust boundaries, sensitive data; a summary, never source code).",
        "parameters": [
          {
            "name": "repo",
            "in": "path",
            "required": true,
            "description": "The repository: its id, or its full name as `owner/name`.",
            "schema": {
              "type": "string",
              "description": "The repository: its id, or its full name as `owner/name`."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/repos/{repo}/scans": {
      "post": {
        "operationId": "start_deep_scan",
        "summary": "Start a deep scan",
        "description": "Starts a deep scan of a whole repository: the hacker reads it end to end for exploitable vulnerabilities (a few minutes). Credits are held now and only what the scan measures is charged; each account's first deep scan is free. One at a time per repository. Then call get_scan with wait to follow it.",
        "parameters": [
          {
            "name": "repo",
            "in": "path",
            "required": true,
            "description": "The repository: its id, or its full name as `owner/name`.",
            "schema": {
              "type": "string",
              "description": "The repository: its id, or its full name as `owner/name`."
            }
          }
        ],
        "responses": {
          "202": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/scans": {
      "get": {
        "operationId": "list_scans",
        "summary": "List scans",
        "description": "Scans the person can see, newest first: PR reviews, deep scans, recon and fix checks, with what each found and the credits it cost. Page with `before` (the last created_at you saw).",
        "parameters": [
          {
            "name": "repo",
            "in": "query",
            "required": false,
            "description": "The repository: its id, or its full name as `owner/name`.",
            "schema": {
              "type": "string",
              "description": "The repository: its id, or its full name as `owner/name`."
            }
          },
          {
            "name": "account",
            "in": "query",
            "required": false,
            "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login.",
            "schema": {
              "type": "string",
              "description": "The GitHub account (user or organization) RedNest is installed on: its id, or its GitHub login."
            }
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "recon",
                "pr_review",
                "deep",
                "fix_check"
              ]
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "Only scans created before this time (ISO 8601), for the next page.",
            "schema": {
              "description": "Only scans created before this time (ISO 8601), for the next page.",
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "At most this many (default 25).",
            "schema": {
              "description": "At most this many (default 25).",
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/scans/{id}": {
      "get": {
        "operationId": "get_scan",
        "summary": "Get a scan",
        "description": "A scan's status and the findings it reported. Pass wait (seconds, up to 50) to hold the request until the scan finishes or the time is up, then call again while done is false. Deep scans take a few minutes.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The scan's id.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The scan's id."
            }
          },
          {
            "name": "wait",
            "in": "query",
            "required": false,
            "description": "Seconds to wait for the scan to finish (0-50).",
            "schema": {
              "description": "Seconds to wait for the scan to finish (0-50).",
              "type": "integer",
              "minimum": 0,
              "maximum": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/scans/{id}/events": {
      "get": {
        "operationId": "get_scan_events",
        "summary": "Follow a scan's feed",
        "description": "The scan's live feed: what the hacker is doing, line by line (stages, files read, findings as they survive verification). Pass `after` (the last seq you saw) for new lines only, and wait (seconds) to hold until there are some.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The scan's id.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The scan's id."
            }
          },
          {
            "name": "after",
            "in": "query",
            "required": false,
            "description": "Only lines after this seq.",
            "schema": {
              "description": "Only lines after this seq.",
              "type": "integer",
              "minimum": 0,
              "maximum": 2147483647
            }
          },
          {
            "name": "wait",
            "in": "query",
            "required": false,
            "description": "Seconds to wait for new lines (0-50).",
            "schema": {
              "description": "Seconds to wait for new lines (0-50).",
              "type": "integer",
              "minimum": 0,
              "maximum": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/findings": {
      "get": {
        "operationId": "list_findings",
        "summary": "List findings",
        "description": "Findings across every repository the person can see, most severe first. Defaults to open findings with low-confidence ones hidden, as the dashboard shows them. Each has a location (the vulnerable line); call get_finding for the attack path, proof of concept and fix prompt.",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Default open.",
            "schema": {
              "description": "Default open.",
              "type": "string",
              "enum": [
                "open",
                "fixed",
                "dismissed"
              ]
            }
          },
          {
            "name": "severity",
            "in": "query",
            "required": false,
            "description": "One severity, a list, or a comma-separated string (\"critical,high\").",
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "enum": [
                    "critical",
                    "high",
                    "medium",
                    "low"
                  ]
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "enum": [
                      "critical",
                      "high",
                      "medium",
                      "low"
                    ]
                  }
                },
                {
                  "type": "string"
                }
              ],
              "description": "One severity, a list, or a comma-separated string (\"critical,high\")."
            }
          },
          {
            "name": "repo",
            "in": "query",
            "required": false,
            "description": "The repository: its id, or its full name as `owner/name`.",
            "schema": {
              "type": "string",
              "description": "The repository: its id, or its full name as `owner/name`."
            }
          },
          {
            "name": "include_low_confidence",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "At most this many (default 100).",
            "schema": {
              "description": "At most this many (default 100).",
              "type": "integer",
              "minimum": 1,
              "maximum": 300
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/findings/prompt": {
      "get": {
        "operationId": "get_findings_prompt",
        "summary": "One prompt for many findings",
        "description": "The findings list as one document, filtered like list_findings: format \"prompt\" (default) is a single prompt for a coding agent to fix every open finding in it, confirming each with a failing regression test first; \"markdown\" is a report with links; \"json\" is the data without code excerpts. Prefer filtering to one repository: the agent fixes only the findings in its own checkout.",
        "parameters": [
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "Default prompt.",
            "schema": {
              "description": "Default prompt.",
              "type": "string",
              "enum": [
                "prompt",
                "markdown",
                "json"
              ]
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Default open. Prompts need open findings.",
            "schema": {
              "description": "Default open. Prompts need open findings.",
              "type": "string",
              "enum": [
                "open",
                "fixed",
                "dismissed"
              ]
            }
          },
          {
            "name": "severity",
            "in": "query",
            "required": false,
            "description": "One severity, a list, or a comma-separated string (\"critical,high\").",
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "enum": [
                    "critical",
                    "high",
                    "medium",
                    "low"
                  ]
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "enum": [
                      "critical",
                      "high",
                      "medium",
                      "low"
                    ]
                  }
                },
                {
                  "type": "string"
                }
              ],
              "description": "One severity, a list, or a comma-separated string (\"critical,high\")."
            }
          },
          {
            "name": "repo",
            "in": "query",
            "required": false,
            "description": "The repository: its id, or its full name as `owner/name`.",
            "schema": {
              "type": "string",
              "description": "The repository: its id, or its full name as `owner/name`."
            }
          },
          {
            "name": "include_low_confidence",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/findings/{id}": {
      "get": {
        "operationId": "get_finding",
        "summary": "Get a finding",
        "description": "Everything about one finding: impact, who can exploit it and how (entry point, attack path with code excerpts, proof of concept), how to fix it without breaking anything, and `fix_prompt`, a ready-to-run prompt for a coding agent. Excerpts and the prompt are removed once a finding is fixed or dismissed.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The finding's id.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The finding's id."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "update_finding",
        "summary": "Fix, dismiss or reopen a finding",
        "description": "Records the person's decision on a finding. status \"dismissed\" needs a reason (false_positive, accepted_risk, wont_fix); \"fixed\" marks it fixed by hand (RedNest also detects fixes merged to the default branch); \"open\" reopens a fixed or dismissed one. Resolving a finding deletes its code excerpts and fix prompt.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The finding's id.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The finding's id."
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "dismissed",
                      "fixed",
                      "open"
                    ]
                  },
                  "reason": {
                    "description": "Why it's dismissed. Required with status \"dismissed\".",
                    "type": "string",
                    "enum": [
                      "false_positive",
                      "accepted_risk",
                      "wont_fix"
                    ]
                  }
                },
                "required": [
                  "status"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/findings/{id}/fix-prompt": {
      "get": {
        "operationId": "get_fix_prompt",
        "summary": "Get a fix prompt",
        "description": "The ready-to-run prompt that fixes an open finding: hand it to a coding agent (or follow it yourself) in a checkout of the repository. It names the vulnerable code, the fix, what must keep working, and a regression test to add. Once the fix is merged to the default branch, RedNest checks it and marks the finding fixed.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The finding's id.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The finding's id."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/overview": {
      "get": {
        "operationId": "get_overview",
        "summary": "Overview",
        "description": "Totals across every repository the person can see over the last `days`: pull requests reviewed, deep scans, findings found and fixed, credits spent, open findings by severity, and a per-day series. Compared with the window before.",
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "required": false,
            "description": "Window length in days (default 30).",
            "schema": {
              "description": "Window length in days (default 30).",
              "type": "integer",
              "minimum": 1,
              "maximum": 90
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "An error: `{ error: { code, message, ... } }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  }
}