{
  "openapi": "3.1.0",
  "info": {
    "title": "Nolvin API",
    "version": "1.0.0",
    "summary": "Agentic knowledge graph infrastructure: build, maintain and query POLE knowledge graphs sourced from the open web.",
    "description": "Describe a domain in one sentence; Nolvin's agents crawl the web and keep a sourced graph of people, objects (organizations), locations and events current. Guides: https://nolvin.com/docs/",
    "contact": {
      "url": "https://nolvin.com/docs/"
    }
  },
  "externalDocs": {
    "description": "Nolvin documentation",
    "url": "https://nolvin.com/docs/"
  },
  "servers": [
    {
      "url": "https://api.nolvin.com"
    }
  ],
  "tags": [
    {
      "name": "API keys",
      "description": "Keys are bound to one project. The plaintext key is returned once, at creation or rotation; only a hash is stored."
    },
    {
      "name": "Project and members",
      "description": "A project is the tenant: it owns keys, members and any number of domains."
    },
    {
      "name": "Domains",
      "description": "A domain is one knowledge graph with its own ontology, sources, gate, budget and entities. Nothing crosses domain boundaries."
    },
    {
      "name": "Autopilot",
      "description": "One sentence in; a brief, discovered sources, a crawled and assessed graph out. Stages: brief → discover → crawling → assess → grow → steady (or failed)."
    },
    {
      "name": "Sources and crawling",
      "description": "Sources are entry points. Crawls stay on source hosts (plus the gate's allowed hosts) within the domain's depth and page budget."
    },
    {
      "name": "Pipeline, runs and usage",
      "description": "Page statuses: queued, extracted, irrelevant, skipped, failed. A page's last mode: agentic (a model read it), deterministic, or unchanged."
    },
    {
      "name": "Gate (spec)",
      "description": "The gate is the domain's versioned relevance rules. Exactly one version is published; the pipeline enforces it."
    },
    {
      "name": "Graph queries",
      "description": "Read-only; any project key works. See the graph queries guide for worked examples."
    },
    {
      "name": "Curation",
      "description": "Human corrections. Every change is audited, and deletes leave a tombstone so a re-scrape does not bring the item back. All curation endpoints need write access."
    },
    {
      "name": "Share links",
      "description": "Read-only public views of a domain behind an unguessable token — no key needed to read them."
    },
    {
      "name": "Webhooks",
      "description": "Signed POSTs when a crawl finishes or a budget is hit. See Webhooks and events for payloads and signature verification."
    },
    {
      "name": "Events and agents",
      "description": "Live progress: poll with a cursor or stream server-sent events."
    },
    {
      "name": "Feedback",
      "description": "Report a problem or an idea; it reaches the team building Nolvin."
    },
    {
      "name": "Service",
      "description": "Unauthenticated."
    }
  ],
  "paths": {
    "/v1/project/keys": {
      "get": {
        "operationId": "getProjectKeys",
        "tags": [
          "API keys"
        ],
        "summary": "List API keys",
        "description": "All keys of the project, newest first, including revoked ones.\n\nAuth: any key. Returns { keys: [{ id, name, scope, created_at, last_used_at, revoked_at }] }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "{ keys: [{ id, name, scope, created_at, last_used_at, revoked_at }] }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-project-keys"
        }
      },
      "post": {
        "operationId": "postProjectKeys",
        "tags": [
          "API keys"
        ],
        "summary": "Create an API key",
        "description": "Auth: owner. Returns { id, key, scope } — key is nlv_… and is shown only once",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "{ id, key, scope } — key is nlv_… and is shown only once"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-project-keys"
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Label for the key (default `key`)."
                  },
                  "scope": {
                    "type": "string",
                    "enum": [
                      "full",
                      "read"
                    ],
                    "description": "`read` keys can only call GET endpoints; anything else creates a `full` key."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/v1/project/keys/{keyId}/rotate": {
      "post": {
        "operationId": "postProjectKeysKeyidRotate",
        "tags": [
          "API keys"
        ],
        "summary": "Rotate an API key",
        "description": "Issues a new secret for the key; the old one stops working immediately.\n\nAuth: owner. Returns { id, key }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "keyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ id, key }"
          },
          "404": {
            "description": "key not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-project-keys-keyid-rotate"
        }
      }
    },
    "/v1/project/keys/{keyId}": {
      "delete": {
        "operationId": "deleteProjectKeysKeyid",
        "tags": [
          "API keys"
        ],
        "summary": "Revoke an API key",
        "description": "Auth: owner. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "keyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#delete-project-keys-keyid"
        }
      }
    },
    "/v1/project": {
      "get": {
        "operationId": "getProject",
        "tags": [
          "Project and members"
        ],
        "summary": "Get the current project",
        "description": "Auth: any key. Returns { id, name, role, scope }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "{ id, name, role, scope }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-project"
        }
      },
      "patch": {
        "operationId": "patchProject",
        "tags": [
          "Project and members"
        ],
        "summary": "Rename the project",
        "description": "Auth: owner. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          },
          "400": {
            "description": "name required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#patch-project"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "New project name."
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteProject",
        "tags": [
          "Project and members"
        ],
        "summary": "Delete the project",
        "description": "Permanently deletes every domain, graph, key, invite and membership of the project.\n\nAuth: owner. Returns { deleted, domains, users }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "confirm",
            "in": "query",
            "required": true,
            "description": "Must equal the project name exactly.",
            "schema": {
              "type": "string",
              "description": "Must equal the project name exactly."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ deleted, domains, users }"
          },
          "400": {
            "description": "pass ?confirm=<project name> to delete",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#delete-project"
        }
      }
    },
    "/v1/project/members": {
      "get": {
        "operationId": "getProjectMembers",
        "tags": [
          "Project and members"
        ],
        "summary": "List members",
        "description": "Auth: any key. Returns { members: [{ id, email, name, role, created_at }] }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "{ members: [{ id, email, name, role, created_at }] }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-project-members"
        }
      }
    },
    "/v1/project/members/{userId}": {
      "patch": {
        "operationId": "patchProjectMembersUserid",
        "tags": [
          "Project and members"
        ],
        "summary": "Change a member's role",
        "description": "Auth: owner. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#patch-project-members-userid"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "role": {
                    "type": "string",
                    "enum": [
                      "owner",
                      "editor",
                      "viewer"
                    ],
                    "description": "New role."
                  }
                },
                "required": [
                  "role"
                ]
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteProjectMembersUserid",
        "tags": [
          "Project and members"
        ],
        "summary": "Remove a member",
        "description": "Auth: owner. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          },
          "400": {
            "description": "cannot remove the last owner",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#delete-project-members-userid"
        }
      }
    },
    "/v1/project/invites": {
      "post": {
        "operationId": "postProjectInvites",
        "tags": [
          "Project and members"
        ],
        "summary": "Create an invite",
        "description": "Auth: owner. Returns { token, role, accept_path }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "{ token, role, accept_path }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-project-invites"
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "role": {
                    "type": "string",
                    "enum": [
                      "editor",
                      "viewer",
                      "owner"
                    ],
                    "description": "Role for the invitee (default `editor`)."
                  }
                },
                "required": []
              }
            }
          }
        }
      },
      "get": {
        "operationId": "getProjectInvites",
        "tags": [
          "Project and members"
        ],
        "summary": "List invites",
        "description": "Auth: any key. Returns { invites: [{ id, role, created_at, accepted_by, accepted_at }] }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "{ invites: [{ id, role, created_at, accepted_by, accepted_at }] }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-project-invites"
        }
      }
    },
    "/v1/domains": {
      "post": {
        "operationId": "postDomains",
        "tags": [
          "Domains"
        ],
        "summary": "Create a domain",
        "description": "Creates an empty domain. To build one from a sentence instead, use autopilot.\n\nAuth: full key. Returns { id, name, ontology }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "{ id, name, ontology }"
          },
          "400": {
            "description": "name is required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Display name."
                  },
                  "description": {
                    "type": "string",
                    "description": "What the graph covers. The extraction agent reads it."
                  },
                  "ontology": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Entity kinds (default `[\"person\",\"object\",\"location\",\"event\"]`)."
                  },
                  "max_depth": {
                    "type": "integer",
                    "description": "Link-follow depth from sources (default 2)."
                  },
                  "max_pages": {
                    "type": "integer",
                    "description": "Page budget (default 100)."
                  },
                  "max_spend_usd": {
                    "type": "number",
                    "description": "Monthly model spend cap in USD (default none)."
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        }
      },
      "get": {
        "operationId": "getDomains",
        "tags": [
          "Domains"
        ],
        "summary": "List domains",
        "description": "Auth: any key. Returns { domains: [{ id, name, description, ontology, max_depth, max_pages, max_spend_usd, archived, crawl_state, created_at, entity_count, page_count }] }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "all",
            "in": "query",
            "required": false,
            "description": "`1` includes archived domains.",
            "schema": {
              "type": "string",
              "description": "`1` includes archived domains."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ domains: [{ id, name, description, ontology, max_depth, max_pages, max_spend_usd, archived, crawl_state, created_at, entity_count, page_count }] }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains"
        }
      }
    },
    "/v1/domains/{domainId}": {
      "get": {
        "operationId": "getDomainsDomainid",
        "tags": [
          "Domains"
        ],
        "summary": "Get a domain",
        "description": "Auth: any key. Returns { id, name, description, ontology, attributes, max_depth, max_pages, max_spend_usd, archived, crawl_state, active_run, published_spec_version, created_at }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ id, name, description, ontology, attributes, max_depth, max_pages, max_spend_usd, archived, crawl_state, active_run, published_spec_version, created_at }"
          },
          "404": {
            "description": "domain not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid"
        }
      },
      "patch": {
        "operationId": "patchDomainsDomainid",
        "tags": [
          "Domains"
        ],
        "summary": "Update a domain",
        "description": "Adding a custom attribute with a new key sends the domain's extracted pages back for a full read on their next re-scrape.\n\nAuth: full key. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          },
          "400": {
            "description": "nothing to update",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#patch-domains-domainid"
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Display name."
                  },
                  "description": {
                    "type": "string",
                    "description": "Scope description."
                  },
                  "ontology": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Entity kinds. Kinds that still have entities cannot be removed."
                  },
                  "attributes": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    },
                    "description": "Custom attributes `[{ key, label, kinds, description }]`, at most 6; `[]` clears them."
                  },
                  "max_depth": {
                    "type": "integer",
                    "description": "Link-follow depth."
                  },
                  "max_pages": {
                    "type": "integer",
                    "description": "Page budget."
                  },
                  "max_spend_usd": {
                    "type": [
                      "number",
                      "null"
                    ],
                    "description": "Monthly spend cap; `null` removes it."
                  }
                },
                "required": []
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteDomainsDomainid",
        "tags": [
          "Domains"
        ],
        "summary": "Delete a domain",
        "description": "Permanently deletes the domain and its whole graph.\n\nAuth: owner. Returns { deleted }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "confirm",
            "in": "query",
            "required": true,
            "description": "Must equal the domain name exactly.",
            "schema": {
              "type": "string",
              "description": "Must equal the domain name exactly."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ deleted }"
          },
          "400": {
            "description": "pass ?confirm=<domain name> to delete",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#delete-domains-domainid"
        }
      }
    },
    "/v1/domains/{domainId}/archive": {
      "post": {
        "operationId": "postDomainsDomainidArchive",
        "tags": [
          "Domains"
        ],
        "summary": "Archive a domain",
        "description": "Stops crawling, re-scrapes and spend. Data is kept.\n\nAuth: full key. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-archive"
        }
      }
    },
    "/v1/domains/{domainId}/unarchive": {
      "post": {
        "operationId": "postDomainsDomainidUnarchive",
        "tags": [
          "Domains"
        ],
        "summary": "Unarchive a domain",
        "description": "Auth: full key. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-unarchive"
        }
      }
    },
    "/v1/domains/{domainId}/scorecard": {
      "get": {
        "operationId": "getDomainsDomainidScorecard",
        "tags": [
          "Domains"
        ],
        "summary": "Graph scorecard",
        "description": "Deterministic 0–100 quality score with components (coverage, precision, connectivity, corroboration, facets, diversity) and the underlying metrics.\n\nAuth: any key. Returns { scorecard: { score, components, metrics } }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ scorecard: { score, components, metrics } }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-scorecard"
        }
      }
    },
    "/v1/domains/autopilot": {
      "post": {
        "operationId": "postDomainsAutopilot",
        "tags": [
          "Autopilot"
        ],
        "summary": "Start an autopilot domain",
        "description": "Auth: full key. Returns { id, stage: \"brief\" }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "202": {
            "description": "{ id, stage: \"brief\" }"
          },
          "400": {
            "description": "prompt too long (max 500 chars)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-autopilot"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "prompt": {
                    "type": "string",
                    "description": "The domain in one sentence, 8–500 characters."
                  },
                  "max_pages": {
                    "type": "integer",
                    "description": "Page budget (default 150)."
                  },
                  "max_spend_usd": {
                    "type": "number",
                    "description": "Monthly spend cap (default 25)."
                  },
                  "max_cycles": {
                    "type": "integer",
                    "description": "Crawl → assess cycles before steady state (default 3)."
                  }
                },
                "required": [
                  "prompt"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/domains/{domainId}/autopilot": {
      "get": {
        "operationId": "getDomainsDomainidAutopilot",
        "tags": [
          "Autopilot"
        ],
        "summary": "Get autopilot state",
        "description": "Auth: any key. Returns { autopilot: { domain_id, prompt, stage, cycle, max_cycles, brief, last_report, history, error, assessed_at, created_at, updated_at } | null }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ autopilot: { domain_id, prompt, stage, cycle, max_cycles, brief, last_report, history, error, assessed_at, created_at, updated_at } | null }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-autopilot"
        }
      }
    },
    "/v1/domains/{domainId}/autopilot/retry": {
      "post": {
        "operationId": "postDomainsDomainidAutopilotRetry",
        "tags": [
          "Autopilot"
        ],
        "summary": "Retry a failed stage",
        "description": "Auth: full key. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          },
          "409": {
            "description": "autopilot is not in a failed state",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-autopilot-retry"
        }
      }
    },
    "/v1/domains/{domainId}/sources": {
      "post": {
        "operationId": "postDomainsDomainidSources",
        "tags": [
          "Sources and crawling"
        ],
        "summary": "Add a source",
        "description": "Registers the URL and queues it immediately.\n\nAuth: full key. Returns { url, queued }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "{ url, queued }"
          },
          "400": {
            "description": "valid http(s) url required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-sources"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "An http(s) URL."
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        }
      },
      "get": {
        "operationId": "getDomainsDomainidSources",
        "tags": [
          "Sources and crawling"
        ],
        "summary": "List sources",
        "description": "Auth: any key. Returns { sources: [{ id, url, created_at, host, pages_seen, pages_extracted }] }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ sources: [{ id, url, created_at, host, pages_seen, pages_extracted }] }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-sources"
        }
      }
    },
    "/v1/domains/{domainId}/sources/bulk": {
      "post": {
        "operationId": "postDomainsDomainidSourcesBulk",
        "tags": [
          "Sources and crawling"
        ],
        "summary": "Add sources in bulk",
        "description": "Auth: full key. Returns { queued }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "{ queued }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-sources-bulk"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "urls": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Up to 100 URLs; invalid ones are skipped."
                  }
                },
                "required": [
                  "urls"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/domains/{domainId}/sources/sitemap": {
      "post": {
        "operationId": "postDomainsDomainidSourcesSitemap",
        "tags": [
          "Sources and crawling"
        ],
        "summary": "Add sources from a sitemap",
        "description": "Auth: full key. Returns { sitemap, discovered, queued }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "{ sitemap, discovered, queued }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-sources-sitemap"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Sitemap URL. The first 50 `<loc>` entries are queued."
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/domains/{domainId}/sources/{sourceId}": {
      "delete": {
        "operationId": "deleteDomainsDomainidSourcesSourceid",
        "tags": [
          "Sources and crawling"
        ],
        "summary": "Remove a source",
        "description": "Removes the source only; its pages and entities stay.\n\nAuth: full key. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sourceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          },
          "404": {
            "description": "source not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#delete-domains-domainid-sources-sourceid"
        }
      }
    },
    "/v1/domains/{domainId}/sources/{sourceId}/crawl": {
      "post": {
        "operationId": "postDomainsDomainidSourcesSourceidCrawl",
        "tags": [
          "Sources and crawling"
        ],
        "summary": "Crawl one source",
        "description": "Auth: full key. Returns { queued }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sourceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ queued }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-sources-sourceid-crawl"
        }
      }
    },
    "/v1/domains/{domainId}/crawl": {
      "post": {
        "operationId": "postDomainsDomainidCrawl",
        "tags": [
          "Sources and crawling"
        ],
        "summary": "Crawl all sources",
        "description": "Queues every source not yet crawled.\n\nAuth: full key. Returns { queued }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ queued }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-crawl"
        }
      }
    },
    "/v1/domains/{domainId}/recrawl": {
      "post": {
        "operationId": "postDomainsDomainidRecrawl",
        "tags": [
          "Sources and crawling"
        ],
        "summary": "Re-scrape the domain now",
        "description": "Queues every extracted page. Unchanged pages cost nothing; changed pages are read as a diff.\n\nAuth: full key. Returns { queued }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ queued }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-recrawl"
        }
      }
    },
    "/v1/domains/{domainId}/discover-sources": {
      "post": {
        "operationId": "postDomainsDomainidDiscoverSources",
        "tags": [
          "Sources and crawling"
        ],
        "summary": "Discover sources",
        "description": "Runs an agentic web search for candidate sources. Results are suggestions: review them and add the ones you want.\n\nAuth: full key. Returns { queued: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "{ queued: true }"
          },
          "409": {
            "description": "a discovery is already running for this domain",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-discover-sources"
        }
      }
    },
    "/v1/domains/{domainId}/discoveries": {
      "get": {
        "operationId": "getDomainsDomainidDiscoveries",
        "tags": [
          "Sources and crawling"
        ],
        "summary": "List discovery runs",
        "description": "Auth: any key. Returns { discoveries: [{ id, status, started_at, finished_at, result, sources: [{ url, reason, kinds }], summary, queries_tried }] } — last 5",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ discoveries: [{ id, status, started_at, finished_at, result, sources: [{ url, reason, kinds }], summary, queries_tried }] } — last 5"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-discoveries"
        }
      }
    },
    "/v1/domains/{domainId}/plan-frontier": {
      "post": {
        "operationId": "postDomainsDomainidPlanFrontier",
        "tags": [
          "Sources and crawling"
        ],
        "summary": "Plan the frontier",
        "description": "Ranks unexplored links, queues the best, and runs gap searches. Also runs weekly on its own.\n\nAuth: full key. Returns { queued: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "{ queued: true }"
          },
          "409": {
            "description": "a frontier plan is already running for this domain",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-plan-frontier"
        }
      }
    },
    "/v1/domains/{domainId}/plans": {
      "get": {
        "operationId": "getDomainsDomainidPlans",
        "tags": [
          "Sources and crawling"
        ],
        "summary": "List frontier plans",
        "description": "Auth: any key. Returns { plans: [{ id, status, started_at, finished_at, result, selected, searches, notes, enqueued, frontier_added }] } — last 5",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ plans: [{ id, status, started_at, finished_at, result, selected, searches, notes, enqueued, frontier_added }] } — last 5"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-plans"
        }
      }
    },
    "/v1/domains/{domainId}/frontier": {
      "get": {
        "operationId": "getDomainsDomainidFrontier",
        "tags": [
          "Sources and crawling"
        ],
        "summary": "Frontier counts",
        "description": "Auth: any key. Returns { frontier: [{ status, n }] } — status: candidate | planned | crawled | rejected",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ frontier: [{ status, n }] } — status: candidate | planned | crawled | rejected"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-frontier"
        }
      }
    },
    "/v1/domains/{domainId}/pages": {
      "get": {
        "operationId": "getDomainsDomainidPages",
        "tags": [
          "Pipeline, runs and usage"
        ],
        "summary": "List pages",
        "description": "Auth: any key. Returns { pages: [{ id, url, depth, status, last_mode, error, source_host, run_id, fetched_at }], next_offset }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter by page status.",
            "schema": {
              "type": "string",
              "description": "Filter by page status."
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size (default 100, max 500).",
            "schema": {
              "type": "integer",
              "description": "Page size (default 100, max 500)."
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Rows to skip (default 0). Use the previous response's `next_offset`.",
            "schema": {
              "type": "integer",
              "description": "Rows to skip (default 0). Use the previous response's `next_offset`."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ pages: [{ id, url, depth, status, last_mode, error, source_host, run_id, fetched_at }], next_offset }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-pages"
        }
      }
    },
    "/v1/domains/{domainId}/runs": {
      "get": {
        "operationId": "getDomainsDomainidRuns",
        "tags": [
          "Pipeline, runs and usage"
        ],
        "summary": "List crawl runs",
        "description": "Auth: any key. Returns { runs: [{ id, status, started_at, finished_at, pages_total, pages_done, pages_unchanged, pages_deterministic, pages_agentic, pages_irrelevant, pages_skipped, pages_failed, entities_added, tokens_input, tokens_output, spend_usd }] } — last 20",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ runs: [{ id, status, started_at, finished_at, pages_total, pages_done, pages_unchanged, pages_deterministic, pages_agentic, pages_irrelevant, pages_skipped, pages_failed, entities_added, tokens_input, tokens_output, spend_usd }] } — last 20"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-runs"
        }
      }
    },
    "/v1/domains/{domainId}/runs/pause": {
      "post": {
        "operationId": "postDomainsDomainidRunsPause",
        "tags": [
          "Pipeline, runs and usage"
        ],
        "summary": "Pause crawling",
        "description": "Auth: full key. Returns { crawl_state: \"paused\" }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ crawl_state: \"paused\" }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-runs-pause"
        }
      }
    },
    "/v1/domains/{domainId}/runs/resume": {
      "post": {
        "operationId": "postDomainsDomainidRunsResume",
        "tags": [
          "Pipeline, runs and usage"
        ],
        "summary": "Resume crawling",
        "description": "Auth: full key. Returns { crawl_state: \"running\", requeued }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ crawl_state: \"running\", requeued }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-runs-resume"
        }
      }
    },
    "/v1/domains/{domainId}/runs/cancel": {
      "post": {
        "operationId": "postDomainsDomainidRunsCancel",
        "tags": [
          "Pipeline, runs and usage"
        ],
        "summary": "Cancel the active run",
        "description": "Auth: full key. Returns { cancelled: true, cancelled_pages }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ cancelled: true, cancelled_pages }"
          },
          "400": {
            "description": "no active run",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-runs-cancel"
        }
      }
    },
    "/v1/domains/{domainId}/recipes": {
      "get": {
        "operationId": "getDomainsDomainidRecipes",
        "tags": [
          "Pipeline, runs and usage"
        ],
        "summary": "List recipes",
        "description": "Legacy deterministic extractors and their health.\n\nAuth: any key. Returns { recipes: [{ id, url, version, status, consecutive_failures, last_run_at, last_error, created_at }] }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ recipes: [{ id, url, version, status, consecutive_failures, last_run_at, last_error, created_at }] }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-recipes"
        }
      }
    },
    "/v1/domains/{domainId}/recipes/{recipeId}/invalidate": {
      "post": {
        "operationId": "postDomainsDomainidRecipesRecipeidInvalidate",
        "tags": [
          "Pipeline, runs and usage"
        ],
        "summary": "Invalidate a recipe",
        "description": "Auth: full key. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "recipeId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          },
          "404": {
            "description": "recipe not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-recipes-recipeid-invalidate"
        }
      }
    },
    "/v1/domains/{domainId}/errors": {
      "get": {
        "operationId": "getDomainsDomainidErrors",
        "tags": [
          "Pipeline, runs and usage"
        ],
        "summary": "List failed pages",
        "description": "Auth: any key. Returns { failed: [{ id, url, depth, error, fetched_at, source_host }] } — last 200",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ failed: [{ id, url, depth, error, fetched_at, source_host }] } — last 200"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-errors"
        }
      }
    },
    "/v1/domains/{domainId}/errors/requeue": {
      "post": {
        "operationId": "postDomainsDomainidErrorsRequeue",
        "tags": [
          "Pipeline, runs and usage"
        ],
        "summary": "Requeue failed pages",
        "description": "Auth: full key. Returns { requeued }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ requeued }"
          },
          "400": {
            "description": "pass page_ids or all=true",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-errors-requeue"
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Up to 100 failed page ids."
                  },
                  "all": {
                    "type": "boolean",
                    "description": "`true` requeues up to 200 failed pages."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/v1/domains/{domainId}/dead-letters": {
      "get": {
        "operationId": "getDomainsDomainidDeadLetters",
        "tags": [
          "Pipeline, runs and usage"
        ],
        "summary": "List dead letters",
        "description": "Pages that failed extraction three times.\n\nAuth: any key. Returns { dead_letters: [{ id, url, depth, error, status, created_at }] }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ dead_letters: [{ id, url, depth, error, status, created_at }] }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-dead-letters"
        }
      }
    },
    "/v1/domains/{domainId}/dead-letters/{deadLetterId}/requeue": {
      "post": {
        "operationId": "postDomainsDomainidDeadLettersDeadletteridRequeue",
        "tags": [
          "Pipeline, runs and usage"
        ],
        "summary": "Requeue a dead letter",
        "description": "Auth: full key. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "deadLetterId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          },
          "404": {
            "description": "not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-dead-letters-deadletterid-requeue"
        }
      }
    },
    "/v1/domains/{domainId}/dead-letters/{deadLetterId}/discard": {
      "post": {
        "operationId": "postDomainsDomainidDeadLettersDeadletteridDiscard",
        "tags": [
          "Pipeline, runs and usage"
        ],
        "summary": "Discard a dead letter",
        "description": "Auth: full key. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "deadLetterId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-dead-letters-deadletterid-discard"
        }
      }
    },
    "/v1/domains/{domainId}/usage": {
      "get": {
        "operationId": "getDomainsDomainidUsage",
        "tags": [
          "Pipeline, runs and usage"
        ],
        "summary": "Usage and spend",
        "description": "Auth: any key. Returns { days: [{ day, pages_unchanged, pages_deterministic, pages_agentic, pages_failed, tokens_input, tokens_output, spend_usd }], totals }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "days",
            "in": "query",
            "required": false,
            "description": "Window in days (default 30, max 90).",
            "schema": {
              "type": "integer",
              "description": "Window in days (default 30, max 90)."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ days: [{ day, pages_unchanged, pages_deterministic, pages_agentic, pages_failed, tokens_input, tokens_output, spend_usd }], totals }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-usage"
        }
      }
    },
    "/v1/domains/{domainId}/spec": {
      "get": {
        "operationId": "getDomainsDomainidSpec",
        "tags": [
          "Gate (spec)"
        ],
        "summary": "List gate versions",
        "description": "Auth: any key. Returns { specs: [{ id, version, status, instructions, include_patterns, exclude_patterns, allowed_hosts, language, created_at, published_at }] }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ specs: [{ id, version, status, instructions, include_patterns, exclude_patterns, allowed_hosts, language, created_at, published_at }] }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-spec"
        }
      },
      "post": {
        "operationId": "postDomainsDomainidSpec",
        "tags": [
          "Gate (spec)"
        ],
        "summary": "Create a draft gate",
        "description": "Auth: full key. Returns { id, version, status: \"draft\" }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "{ id, version, status: \"draft\" }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-spec"
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "instructions": {
                    "type": "string",
                    "description": "Plain-language inclusion and exclusion rules the extraction agent applies."
                  },
                  "include_patterns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "URL patterns a page must match (substring, or glob with `*`)."
                  },
                  "exclude_patterns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "URL patterns never to crawl."
                  },
                  "allowed_hosts": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Hosts in scope beyond the source hosts."
                  },
                  "language": {
                    "type": "string",
                    "description": "ISO 639-1 language for descriptions."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/v1/domains/{domainId}/spec/{specId}/publish": {
      "post": {
        "operationId": "postDomainsDomainidSpecSpecidPublish",
        "tags": [
          "Gate (spec)"
        ],
        "summary": "Publish a gate version",
        "description": "Auth: full key. Returns { ok: true, version }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "specId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "rejudge",
            "in": "query",
            "required": false,
            "description": "`1` gives pages the old gate rejected a second look.",
            "schema": {
              "type": "string",
              "description": "`1` gives pages the old gate rejected a second look."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true, version }"
          },
          "404": {
            "description": "spec not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-spec-specid-publish"
        }
      }
    },
    "/v1/domains/{domainId}/dry-run": {
      "post": {
        "operationId": "postDomainsDomainidDryRun",
        "tags": [
          "Gate (spec)"
        ],
        "summary": "Test a gate on one URL",
        "description": "Fetch, gate and extract one page without writing to the graph. Costs one extraction.\n\nAuth: full key. Returns { url, gate_rejection, relevant, confidence, page_class, entities, relationships, next_urls, model, cost_usd, markdown, tokens }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ url, gate_rejection, relevant, confidence, page_class, entities, relationships, next_urls, model, cost_usd, markdown, tokens }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-dry-run"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Page to test."
                  },
                  "spec_id": {
                    "type": "string",
                    "description": "Draft gate to test (default: the published one)."
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/domains/{domainId}/entities": {
      "get": {
        "operationId": "getDomainsDomainidEntities",
        "tags": [
          "Graph queries"
        ],
        "summary": "List entities",
        "description": "Auth: any key. Returns { entities: [{ id, type, name, description, aliases, created_at, updated_at }], next_offset }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "person, object, location or event.",
            "schema": {
              "type": "string",
              "description": "person, object, location or event."
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Substring match on name or description.",
            "schema": {
              "type": "string",
              "description": "Substring match on name or description."
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size (default 50, max 200).",
            "schema": {
              "type": "integer",
              "description": "Page size (default 50, max 200)."
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Rows to skip (default 0). Use the previous response's `next_offset`.",
            "schema": {
              "type": "integer",
              "description": "Rows to skip (default 0). Use the previous response's `next_offset`."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ entities: [{ id, type, name, description, aliases, created_at, updated_at }], next_offset }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-entities"
        }
      }
    },
    "/v1/domains/{domainId}/entities/{entityId}": {
      "get": {
        "operationId": "getDomainsDomainidEntitiesEntityid",
        "tags": [
          "Graph queries"
        ],
        "summary": "Get an entity",
        "description": "The entity with its facet, custom attributes, relationships and up to 50 provenance rows.\n\nAuth: any key. Returns { entity, facet, attributes, relationships: [{ relation, direction, entity_id, name, type }], provenance: [{ snippet, url, created_at }] }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "entityId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ entity, facet, attributes, relationships: [{ relation, direction, entity_id, name, type }], provenance: [{ snippet, url, created_at }] }"
          },
          "404": {
            "description": "not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-entities-entityid"
        }
      }
    },
    "/v1/domains/{domainId}/entities/{entityId}/neighbors": {
      "get": {
        "operationId": "getDomainsDomainidEntitiesEntityidNeighbors",
        "tags": [
          "Graph queries"
        ],
        "summary": "Traverse the neighborhood",
        "description": "Auth: any key. Returns { root, nodes: [{ id, name, type }], edges: [{ source, relation, target }] }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "entityId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "depth",
            "in": "query",
            "required": false,
            "description": "Hops, 1–3 (default 1).",
            "schema": {
              "type": "integer",
              "description": "Hops, 1–3 (default 1)."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ root, nodes: [{ id, name, type }], edges: [{ source, relation, target }] }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-entities-entityid-neighbors"
        }
      }
    },
    "/v1/domains/{domainId}/relationships": {
      "get": {
        "operationId": "getDomainsDomainidRelationships",
        "tags": [
          "Graph queries"
        ],
        "summary": "List relationships",
        "description": "Auth: any key. Returns { relationships: [{ id, relation, source_entity_id, target_entity_id, source_name, source_type, target_name, target_type }] } — up to 500",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "relation",
            "in": "query",
            "required": false,
            "description": "One canonical predicate, e.g. `organizes`.",
            "schema": {
              "type": "string",
              "description": "One canonical predicate, e.g. `organizes`."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ relationships: [{ id, relation, source_entity_id, target_entity_id, source_name, source_type, target_name, target_type }] } — up to 500"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-relationships"
        }
      }
    },
    "/v1/domains/{domainId}/search": {
      "get": {
        "operationId": "getDomainsDomainidSearch",
        "tags": [
          "Graph queries"
        ],
        "summary": "Search entities",
        "description": "Keyword and semantic search merged, best first.\n\nAuth: any key. Returns { results: [{ id, type, name, description, match, score }], semantic_enabled }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Search text.",
            "schema": {
              "type": "string",
              "description": "Search text."
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Restrict to one kind.",
            "schema": {
              "type": "string",
              "description": "Restrict to one kind."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ results: [{ id, type, name, description, match, score }], semantic_enabled }"
          },
          "400": {
            "description": "q is required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-search"
        }
      }
    },
    "/v1/domains/{domainId}/timeline": {
      "get": {
        "operationId": "getDomainsDomainidTimeline",
        "tags": [
          "Graph queries"
        ],
        "summary": "Timeline",
        "description": "Events with their participants, ordered by start. With `entity_id`, the events connected to any entity.\n\nAuth: any key. Returns { timeline: [{ id, name, description, starts_at, ends_at, participants }] } or { granularity, buckets: [{ bucket, n }] }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Earliest `starts_at` (ISO date).",
            "schema": {
              "type": "string",
              "description": "Earliest `starts_at` (ISO date)."
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Latest `starts_at`.",
            "schema": {
              "type": "string",
              "description": "Latest `starts_at`."
            }
          },
          {
            "name": "entity_id",
            "in": "query",
            "required": false,
            "description": "Project one entity onto the timeline.",
            "schema": {
              "type": "string",
              "description": "Project one entity onto the timeline."
            }
          },
          {
            "name": "granularity",
            "in": "query",
            "required": false,
            "description": "Return counts per bucket instead of events.",
            "schema": {
              "type": "string",
              "enum": [
                "year",
                "month",
                "day"
              ],
              "description": "Return counts per bucket instead of events."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ timeline: [{ id, name, description, starts_at, ends_at, participants }] } or { granularity, buckets: [{ bucket, n }] }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-timeline"
        }
      }
    },
    "/v1/domains/{domainId}/geo.geojson": {
      "get": {
        "operationId": "getDomainsDomainidGeoGeojson",
        "tags": [
          "Graph queries"
        ],
        "summary": "Map (GeoJSON)",
        "description": "Located entities as a GeoJSON FeatureCollection, each with its connected entities. With `entity_id`, one entity's footprint.\n\nAuth: any key. Returns GeoJSON FeatureCollection — properties: { entity_id, name, description, address, connected }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "entity_id",
            "in": "query",
            "required": false,
            "description": "Project one entity onto the map.",
            "schema": {
              "type": "string",
              "description": "Project one entity onto the map."
            }
          },
          {
            "name": "bbox",
            "in": "query",
            "required": false,
            "description": "`minLng,minLat,maxLng,maxLat`.",
            "schema": {
              "type": "string",
              "description": "`minLng,minLat,maxLng,maxLat`."
            }
          },
          {
            "name": "cluster",
            "in": "query",
            "required": false,
            "description": "`1` returns grid clusters with counts.",
            "schema": {
              "type": "string",
              "description": "`1` returns grid clusters with counts."
            }
          },
          {
            "name": "cell",
            "in": "query",
            "required": false,
            "description": "Cluster cell size in degrees (default 2, min 0.25).",
            "schema": {
              "type": "number",
              "description": "Cluster cell size in degrees (default 2, min 0.25)."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "GeoJSON FeatureCollection — properties: { entity_id, name, description, address, connected }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-geo-geojson"
        }
      }
    },
    "/v1/domains/{domainId}/stats": {
      "get": {
        "operationId": "getDomainsDomainidStats",
        "tags": [
          "Graph queries"
        ],
        "summary": "Graph statistics",
        "description": "Auth: any key. Returns { totals: { entities, relationships, facts, pages }, entities_by_type, top_relations, pages_by_status, pages_by_mode, recipes_by_status }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ totals: { entities, relationships, facts, pages }, entities_by_type, top_relations, pages_by_status, pages_by_mode, recipes_by_status }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-stats"
        }
      }
    },
    "/v1/domains/{domainId}/export": {
      "get": {
        "operationId": "getDomainsDomainidExport",
        "tags": [
          "Graph queries"
        ],
        "summary": "Export the graph",
        "description": "Auth: any key. Returns { domain, entities, relationships, facets: { locations, events, persons, objects, attributes } } or GraphML",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "Default `json`.",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "graphml"
              ],
              "description": "Default `json`."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ domain, entities, relationships, facets: { locations, events, persons, objects, attributes } } or GraphML"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-export"
        }
      }
    },
    "/v1/domains/{domainId}/curation/entities/{entityId}/rename": {
      "post": {
        "operationId": "postDomainsDomainidCurationEntitiesEntityidRename",
        "tags": [
          "Curation"
        ],
        "summary": "Rename an entity",
        "description": "The old name is kept as an alias.\n\nAuth: full key. Returns { ok: true, name }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "entityId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true, name }"
          },
          "409": {
            "description": "an entity of this type with that name exists — merge instead",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-curation-entities-entityid-rename"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "New name."
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/domains/{domainId}/curation/entities/{entityId}/merge": {
      "post": {
        "operationId": "postDomainsDomainidCurationEntitiesEntityidMerge",
        "tags": [
          "Curation"
        ],
        "summary": "Merge into another entity",
        "description": "This entity's edges, provenance and names move to the survivor.\n\nAuth: full key. Returns { ok: true, survivor, aliases }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "entityId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true, survivor, aliases }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-curation-entities-entityid-merge"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "into": {
                    "type": "string",
                    "description": "Survivor entity id."
                  }
                },
                "required": [
                  "into"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/domains/{domainId}/curation/entities/{entityId}/facet": {
      "patch": {
        "operationId": "patchDomainsDomainidCurationEntitiesEntityidFacet",
        "tags": [
          "Curation"
        ],
        "summary": "Replace an entity's facet",
        "description": "Replaces the whole facet; omitted fields become null. Location: lat, lng, address. Event: starts_at, ends_at. Person: aliases, role. Object: category, identifier.\n\nAuth: full key. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "entityId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#patch-domains-domainid-curation-entities-entityid-facet"
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      }
    },
    "/v1/domains/{domainId}/curation/entities/{entityId}": {
      "delete": {
        "operationId": "deleteDomainsDomainidCurationEntitiesEntityid",
        "tags": [
          "Curation"
        ],
        "summary": "Delete an entity",
        "description": "Auth: full key. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "entityId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#delete-domains-domainid-curation-entities-entityid"
        }
      }
    },
    "/v1/domains/{domainId}/curation/relationships/{relationshipId}": {
      "delete": {
        "operationId": "deleteDomainsDomainidCurationRelationshipsRelationshipid",
        "tags": [
          "Curation"
        ],
        "summary": "Delete a relationship",
        "description": "Auth: full key. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "relationshipId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#delete-domains-domainid-curation-relationships-relationshipid"
        }
      }
    },
    "/v1/domains/{domainId}/curation/audit": {
      "get": {
        "operationId": "getDomainsDomainidCurationAudit",
        "tags": [
          "Curation"
        ],
        "summary": "Curation audit log",
        "description": "Auth: full key. Returns { audit: [{ id, user_id, action, subject_id, details, created_at }] } — last 100",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ audit: [{ id, user_id, action, subject_id, details, created_at }] } — last 100"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-curation-audit"
        }
      }
    },
    "/v1/domains/{domainId}/share": {
      "post": {
        "operationId": "postDomainsDomainidShare",
        "tags": [
          "Share links"
        ],
        "summary": "Create a share link",
        "description": "Auth: full key. Returns { id, token, views, public_base } — token is shr_… and is shown only once",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "{ id, token, views, public_base } — token is shr_… and is shown only once"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-share"
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "views": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Any of graph, timeline, map, search (default all)."
                  }
                },
                "required": []
              }
            }
          }
        }
      },
      "get": {
        "operationId": "getDomainsDomainidShare",
        "tags": [
          "Share links"
        ],
        "summary": "List share links",
        "description": "Auth: any key. Returns { shares: [{ id, views, created_at, revoked_at }] }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ shares: [{ id, views, created_at, revoked_at }] }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-share"
        }
      }
    },
    "/v1/domains/{domainId}/share/{shareId}": {
      "delete": {
        "operationId": "deleteDomainsDomainidShareShareid",
        "tags": [
          "Share links"
        ],
        "summary": "Revoke a share link",
        "description": "Auth: full key. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "shareId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#delete-domains-domainid-share-shareid"
        }
      }
    },
    "/v1/public/{token}/meta": {
      "get": {
        "operationId": "getPublicTokenMeta",
        "tags": [
          "Share links"
        ],
        "summary": "Shared domain metadata",
        "description": "Auth: share token. Returns { name, description, views }",
        "security": [],
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ name, description, views }"
          },
          "404": {
            "description": "invalid share token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-public-token-meta"
        }
      }
    },
    "/v1/public/{token}/entities": {
      "get": {
        "operationId": "getPublicTokenEntities",
        "tags": [
          "Share links"
        ],
        "summary": "Shared entities",
        "description": "Needs the graph or search view.\n\nAuth: share token. Returns { entities: [{ id, type, name, description }] }",
        "security": [],
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Default 100, max 200.",
            "schema": {
              "type": "integer",
              "description": "Default 100, max 200."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ entities: [{ id, type, name, description }] }"
          },
          "403": {
            "description": "view not shared",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-public-token-entities"
        }
      }
    },
    "/v1/public/{token}/timeline": {
      "get": {
        "operationId": "getPublicTokenTimeline",
        "tags": [
          "Share links"
        ],
        "summary": "Shared timeline",
        "description": "Needs the timeline view.\n\nAuth: share token. Returns { timeline: [{ id, name, description, starts_at, ends_at }] }",
        "security": [],
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ timeline: [{ id, name, description, starts_at, ends_at }] }"
          },
          "403": {
            "description": "view not shared",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-public-token-timeline"
        }
      }
    },
    "/v1/public/{token}/geo.geojson": {
      "get": {
        "operationId": "getPublicTokenGeoGeojson",
        "tags": [
          "Share links"
        ],
        "summary": "Shared map",
        "description": "Needs the map view.\n\nAuth: share token. Returns GeoJSON FeatureCollection",
        "security": [],
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "GeoJSON FeatureCollection"
          },
          "403": {
            "description": "view not shared",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-public-token-geo-geojson"
        }
      }
    },
    "/v1/domains/{domainId}/webhooks": {
      "get": {
        "operationId": "getDomainsDomainidWebhooks",
        "tags": [
          "Webhooks"
        ],
        "summary": "List webhooks",
        "description": "Auth: any key. Returns { webhooks: [{ id, url, events, active, created_at }] }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ webhooks: [{ id, url, events, active, created_at }] }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-webhooks"
        }
      },
      "post": {
        "operationId": "postDomainsDomainidWebhooks",
        "tags": [
          "Webhooks"
        ],
        "summary": "Create a webhook",
        "description": "Auth: full key. Returns { id, secret, events } — secret is whsec_… and is shown only once",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "{ id, secret, events } — secret is whsec_… and is shown only once"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-webhooks"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Receiver URL."
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Any of crawl.finished, budget.hit (default crawl.finished)."
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/domains/{domainId}/webhooks/{webhookId}/rotate-secret": {
      "post": {
        "operationId": "postDomainsDomainidWebhooksWebhookidRotateSecret",
        "tags": [
          "Webhooks"
        ],
        "summary": "Rotate a webhook secret",
        "description": "Auth: full key. Returns { secret }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ secret }"
          },
          "404": {
            "description": "webhook not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-webhooks-webhookid-rotate-secret"
        }
      }
    },
    "/v1/domains/{domainId}/webhooks/{webhookId}": {
      "delete": {
        "operationId": "deleteDomainsDomainidWebhooksWebhookid",
        "tags": [
          "Webhooks"
        ],
        "summary": "Delete a webhook",
        "description": "Auth: full key. Returns { ok: true }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#delete-domains-domainid-webhooks-webhookid"
        }
      }
    },
    "/v1/domains/{domainId}/webhooks/{webhookId}/test": {
      "post": {
        "operationId": "postDomainsDomainidWebhooksWebhookidTest",
        "tags": [
          "Webhooks"
        ],
        "summary": "Send a test delivery",
        "description": "Dispatches a test `crawl.finished` to the domain's subscribed webhooks.\n\nAuth: full key. Returns { ok: true, note }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true, note }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-domains-domainid-webhooks-webhookid-test"
        }
      }
    },
    "/v1/domains/{domainId}/webhooks/{webhookId}/deliveries": {
      "get": {
        "operationId": "getDomainsDomainidWebhooksWebhookidDeliveries",
        "tags": [
          "Webhooks"
        ],
        "summary": "List deliveries",
        "description": "Auth: any key. Returns { deliveries: [{ id, event_type, payload, status, attempts, last_error, created_at, delivered_at }] } — last 50",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ deliveries: [{ id, event_type, payload, status, attempts, last_error, created_at, delivered_at }] } — last 50"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-webhooks-webhookid-deliveries"
        }
      }
    },
    "/v1/domains/{domainId}/events/poll": {
      "get": {
        "operationId": "getDomainsDomainidEventsPoll",
        "tags": [
          "Events and agents"
        ],
        "summary": "Poll domain events",
        "description": "Auth: any key. Returns { events: [{ id, type, payload, created_at }], cursor }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Cursor from the previous response (default 0).",
            "schema": {
              "type": "integer",
              "description": "Cursor from the previous response (default 0)."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ events: [{ id, type, payload, created_at }], cursor }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-events-poll"
        }
      }
    },
    "/v1/domains/{domainId}/events": {
      "get": {
        "operationId": "getDomainsDomainidEvents",
        "tags": [
          "Events and agents"
        ],
        "summary": "Stream domain events (SSE)",
        "description": "Events: run.update, page.update, crawl.finished, budget.hit. Resumes from `Last-Event-ID`; the server closes the stream after about four minutes, so reconnect.\n\nAuth: any key. Returns text/event-stream",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Start after this event id.",
            "schema": {
              "type": "integer",
              "description": "Start after this event id."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "text/event-stream"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-domains-domainid-events"
        }
      }
    },
    "/v1/agents": {
      "get": {
        "operationId": "getAgents",
        "tags": [
          "Events and agents"
        ],
        "summary": "List agent runs",
        "description": "Auth: any key. Returns { agents: [{ id, kind, label, status, started_at, finished_at, tokens_input, tokens_output, result, domain_name, domain_id }] }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "{ agents: [{ id, kind, label, status, started_at, finished_at, tokens_input, tokens_output, result, domain_name, domain_id }] }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-agents"
        }
      }
    },
    "/v1/agents/{runId}/activity": {
      "get": {
        "operationId": "getAgentsRunidActivity",
        "tags": [
          "Events and agents"
        ],
        "summary": "Agent run activity",
        "description": "Auth: any key. Returns { run, activity: [{ id, ts, text }] }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "runId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ run, activity: [{ id, ts, text }] }"
          },
          "404": {
            "description": "agent run not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-agents-runid-activity"
        }
      }
    },
    "/v1/agents/activity/poll": {
      "get": {
        "operationId": "getAgentsActivityPoll",
        "tags": [
          "Events and agents"
        ],
        "summary": "Poll agent activity",
        "description": "Auth: any key. Returns { activity: [{ id, ts, text, agent_run_id, kind, label, status }], cursor }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Cursor (default 0).",
            "schema": {
              "type": "integer",
              "description": "Cursor (default 0)."
            }
          },
          {
            "name": "tail",
            "in": "query",
            "required": false,
            "description": "Return the last N rows instead (max 200).",
            "schema": {
              "type": "integer",
              "description": "Return the last N rows instead (max 200)."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ activity: [{ id, ts, text, agent_run_id, kind, label, status }], cursor }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-agents-activity-poll"
        }
      }
    },
    "/v1/agents/events": {
      "get": {
        "operationId": "getAgentsEvents",
        "tags": [
          "Events and agents"
        ],
        "summary": "Stream agent activity (SSE)",
        "description": "Event name: agent.activity.\n\nAuth: any key. Returns text/event-stream",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "text/event-stream"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-agents-events"
        }
      }
    },
    "/v1/feedback": {
      "post": {
        "operationId": "postFeedback",
        "tags": [
          "Feedback"
        ],
        "summary": "Send feedback",
        "description": "Auth: any key. Returns { id, status: \"new\" }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "{ id, status: \"new\" }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#post-feedback"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "pathname": {
                    "type": "string",
                    "description": "Where it happened."
                  },
                  "full_url": {
                    "type": "string",
                    "description": "Full URL."
                  },
                  "description": {
                    "type": "string",
                    "description": "What you saw or want (max 20,000 characters)."
                  },
                  "category": {
                    "type": "string",
                    "enum": [
                      "idea",
                      "bug",
                      "critical",
                      "other"
                    ],
                    "description": "Default idea."
                  },
                  "selector": {
                    "type": "string",
                    "description": "CSS selector of the element concerned."
                  }
                },
                "required": [
                  "pathname",
                  "full_url",
                  "description"
                ]
              }
            }
          }
        }
      },
      "get": {
        "operationId": "getFeedback",
        "tags": [
          "Feedback"
        ],
        "summary": "List your feedback",
        "description": "Auth: any key. Returns { feedback: [{ id, category, status, description, fix_url, fix_summary, created_at, … }] }",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter (default all).",
            "schema": {
              "type": "string",
              "enum": [
                "new",
                "in_progress",
                "shipped",
                "closed",
                "all"
              ],
              "description": "Filter (default all)."
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Default 50, max 200.",
            "schema": {
              "type": "integer",
              "description": "Default 50, max 200."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ feedback: [{ id, category, status, description, fix_url, fix_summary, created_at, … }] }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-feedback"
        }
      }
    },
    "/api": {
      "get": {
        "operationId": "getApi",
        "tags": [
          "Service"
        ],
        "summary": "Service description",
        "description": "Auth: no auth. Returns { name, description, docs }",
        "security": [],
        "responses": {
          "200": {
            "description": "{ name, description, docs }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-api"
        }
      }
    },
    "/healthz": {
      "get": {
        "operationId": "getHealthz",
        "tags": [
          "Service"
        ],
        "summary": "Health check",
        "description": "503 when the database is unreachable or the scheduler is stale.\n\nAuth: no auth. Returns { ok, db, cron, cron_age_minutes, queued_pages, dead_pages_pending }",
        "security": [],
        "responses": {
          "200": {
            "description": "{ ok, db, cron, cron_age_minutes, queued_pages, dead_pages_pending }"
          }
        },
        "externalDocs": {
          "url": "https://nolvin.com/docs/api-reference#get-healthz"
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "nlv_…",
        "description": "Project API key. Read-scope keys can call GET endpoints only."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "request_id": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ]
      }
    }
  }
}
