{
  "openapi": "3.1.0",
  "info": {
    "title": "Analytiics HTTP API",
    "version": "1.1.0",
    "summary": "Send events to Analytiics, manage projects and keys, and read public dashboards.",
    "description": "Analytiics is web and product analytics where the tracking plan lives in your git\nrepository: one `analytics.yaml` manifest generates a typed SDK, the dashboard\nsections and a CI drift check.\n\nThis API has two hosts and they are not interchangeable:\n\n- **The collector**, `https://in.analytiics.co`, takes events. `POST /v1/events` is public and\n  unauthenticated because it ships to every visitor — which is exactly why it ignores\n  revenue. `POST /v1/server/events` is authenticated with a project write key and is the\n  only path that may carry money or identity.\n- **The app**, `https://www.analytiics.co`, manages projects and write keys and serves public\n  dashboard data. Its management endpoints authenticate with a session token from\n  `analytiics login`.\n\nEvery failure on either host returns the same JSON `Error` body with a stable `code`.\nSee the `Error` schema for what to switch on.",
    "contact": {
      "name": "Analytiics",
      "url": "https://www.analytiics.co/contact",
      "email": "hello@analytiics.co"
    },
    "x-logo": {
      "url": "https://www.analytiics.co/icon.svg",
      "altText": "Analytiics"
    }
  },
  "servers": [
    {
      "url": "https://www.analytiics.co",
      "description": "The Analytiics app."
    },
    {
      "url": "https://in.analytiics.co",
      "description": "The Analytiics event collector."
    }
  ],
  "externalDocs": {
    "description": "The Analytiics HTTP API reference, in prose.",
    "url": "https://www.analytiics.co/docs/api"
  },
  "tags": [
    {
      "name": "Events",
      "description": "Getting data in. The browser path is public and refuses revenue; the server path is authenticated and accepts it."
    },
    {
      "name": "Projects",
      "description": "Managing projects and their write keys. Authenticated as the person who signed in."
    },
    {
      "name": "Dashboards",
      "description": "Reading and publishing what a project's dashboard shows."
    },
    {
      "name": "Account",
      "description": "The account behind the projects: which plan it is on, what it has used, and how to move it onto another one."
    },
    {
      "name": "Meta",
      "description": "Liveness, the tracker script, and the waitlist."
    }
  ],
  "paths": {
    "/v1/events": {
      "servers": [
        {
          "url": "https://in.analytiics.co",
          "description": "The Analytiics event collector."
        }
      ],
      "post": {
        "operationId": "collectBrowserEvents",
        "summary": "Record events from a browser",
        "description": "The endpoint the browser tracker calls. Public, CORS-open, and unauthenticated: the\nsnippet that calls it is readable in every visitor's page source.\n\n**It ignores `revenue_cents` and `currency` outright.** Anyone who can read your page\nsource could otherwise post fake sales into your dashboard. Send money from your\nbackend with `collectServerEvents` instead.\n\nLocation, device, browser and OS are derived from the request headers. Anonymous ids\nare a salted daily-rotating hash of IP, user agent and project; raw IP addresses are\nnever stored, and there is no cookie.\n\nUp to 50 events per request. Traffic identified as a bot is dropped silently with\n`202 {\"accepted\": 0}` — a success, not something to retry.\n\nEvents are only recorded for a project that exists, from pages on its domain. A `site`\nnobody has created is refused with `404 project_not_found`, and the whole batch with\nit: create the project first, and make sure the snippet's `data-site` is its domain\nexactly. A page that is not on that domain (or a subdomain of it) is refused with\n`403 site_mismatch` — the snippet is on the wrong site. When the collector\ncannot check — its control plane is unreachable and it has no recent answer for that\nsite — it answers `503 unavailable` and records nothing, rather than guess.",
        "tags": [
          "Events"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "description": "The tracker posts this with `Content-Type: text/plain` so the request stays a CORS simple request and skips the preflight. The body is parsed as JSON either way.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "events"
                ],
                "additionalProperties": false,
                "properties": {
                  "events": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 50,
                    "items": {
                      "$ref": "#/components/schemas/BrowserEvent"
                    }
                  }
                }
              },
              "example": {
                "events": [
                  {
                    "site": "your-project",
                    "name": "page_published",
                    "url": "https://example.com/editor",
                    "ref": "https://www.google.com/",
                    "sid": "s_8f21",
                    "uid": "",
                    "props": {
                      "template": "grid"
                    }
                  }
                ]
              }
            },
            "text/plain": {
              "schema": {
                "type": "string",
                "description": "The same JSON body, sent with a content type that avoids a preflight."
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted. `accepted` is the number of rows written — `0` means the caller was a bot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Accepted"
                },
                "example": {
                  "accepted": 1
                }
              }
            }
          },
          "400": {
            "description": "The body was not JSON, or did not validate.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: invalid_json, invalid_payload."
                },
                "examples": {
                  "invalid_json": {
                    "$ref": "#/components/examples/error_invalid_json"
                  },
                  "invalid_payload": {
                    "$ref": "#/components/examples/error_invalid_payload"
                  }
                }
              }
            }
          },
          "403": {
            "description": "An event's `url` is not on its `site`'s domain or a subdomain of it. Nothing was recorded. Projects created before domains were the rule have no domain to check against and never get this.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: site_mismatch."
                },
                "examples": {
                  "site_mismatch": {
                    "$ref": "#/components/examples/error_site_mismatch"
                  }
                }
              }
            }
          },
          "404": {
            "description": "A `site` in the batch names a project that does not exist. Nothing was recorded.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: project_not_found."
                },
                "examples": {
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts POST, OPTIONS.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "POST, OPTIONS"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "503": {
            "description": "The collector could not check whether a `site` exists. Nothing was recorded; retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/server/events": {
      "servers": [
        {
          "url": "https://in.analytiics.co",
          "description": "The Analytiics event collector."
        }
      ],
      "post": {
        "operationId": "collectServerEvents",
        "summary": "Record events from your backend, including revenue",
        "description": "Server-to-server, authenticated with a project write key. This is the only path that\nmay set revenue, and it deliberately sends no CORS headers — a write key\nin a browser bundle is a write key you have to rotate.\n\nOne project per request: the key authorizes exactly the project named in `site`, so a\nbatch cannot smuggle rows into a neighbour's data. Up to 200 events per request.\n\n`revenue_cents` requires `currency`. Timestamps are accepted up to 30 days old,\nbecause webhook providers retry for days.\n\nA 401 is the same answer whether the key is wrong or the project does not exist, so\nthis cannot be used to enumerate projects. A 503 means authorization or durable delivery\ncould not be confirmed. Retry with the same event_id values and backoff; a partial write\nmay have committed. 202 confirms every logical event is stored (including prior deliveries).\nEach event needs a stable event_id; older SDKs must be upgraded before using this contract.",
        "tags": [
          "Events"
        ],
        "security": [
          {
            "writeKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "site",
                  "events"
                ],
                "additionalProperties": false,
                "properties": {
                  "site": {
                    "$ref": "#/components/schemas/ProjectSlug"
                  },
                  "events": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 200,
                    "items": {
                      "$ref": "#/components/schemas/ServerEvent"
                    }
                  }
                }
              },
              "example": {
                "site": "your-project",
                "events": [
                  {
                    "event_id": "evt_provider_123",
                    "name": "subscription_started",
                    "user_id": "usr_123",
                    "revenue_cents": 2900,
                    "currency": "USD",
                    "props": {
                      "plan": "pro"
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Accepted"
                },
                "example": {
                  "accepted": 1
                }
              }
            }
          },
          "400": {
            "description": "The body was not JSON, or did not validate. `detail` names the first failure.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: invalid_json, invalid_payload."
                },
                "examples": {
                  "invalid_json": {
                    "$ref": "#/components/examples/error_invalid_json"
                  },
                  "invalid_payload": {
                    "$ref": "#/components/examples/error_invalid_payload"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, malformed or unknown write key — or a `site` this key does not authorize. Deliberately indistinguishable from a project that does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts POST.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "POST"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "409": {
            "description": "An event ID was reused with different event data.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: event_conflict."
                },
                "examples": {
                  "event_conflict": {
                    "$ref": "#/components/examples/error_event_conflict"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Authorization or durable delivery could not be confirmed. Retry with the same event IDs and backoff.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: key_verification_unavailable, unavailable."
                },
                "examples": {
                  "key_verification_unavailable": {
                    "$ref": "#/components/examples/error_key_verification_unavailable"
                  },
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/health": {
      "servers": [
        {
          "url": "https://in.analytiics.co",
          "description": "The Analytiics event collector."
        }
      ],
      "get": {
        "operationId": "getCollectorHealth",
        "summary": "Check that the collector is up",
        "description": "Liveness only. No authentication, no dependencies checked.",
        "tags": [
          "Meta"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "The collector is up.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/script.js": {
      "servers": [
        {
          "url": "https://in.analytiics.co",
          "description": "The Analytiics event collector."
        }
      ],
      "get": {
        "operationId": "getTrackerScript",
        "summary": "Fetch the browser tracker",
        "description": "The tracker itself, under 2 KB gzipped, cached and CORS-open.\n\nInstall it as a deferred script element pointing at this URL, with `data-site` set to\nyour project's domain — the copyable snippet is in the quickstart at\nhttps://www.analytiics.co/docs/quickstart. Serving the same file from your own domain instead\nsurvives the blocklists a third-party analytics host does not; set `data-api` to this\nhost so events still reach the collector.\n\nThe path is named for what the file is rather than for us: filter lists carry rules\nthat match a path on any host, so a vendor-shaped filename would follow you onto your\nown collector domain. The same script is also served at `/aii.js`, the name it had\nfirst.",
        "tags": [
          "Meta"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "The tracker source.",
            "content": {
              "application/javascript": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "This deployment was built without the tracker bundled. Fetch it from npm (`@analytiics/tracker`) instead.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: not_found."
                },
                "examples": {
                  "not_found": {
                    "$ref": "#/components/examples/error_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/online": {
      "get": {
        "operationId": "getOnlineCount",
        "summary": "Read a project's public live visitor count without the activity feed",
        "description": "Returns only the number of people seen in the last five minutes. Use this for\nlive stats pills: it never queries the activity feed. Poll every 30 seconds while\nvisible; upstream results share a 30-second cache.\nPublication and the realtime widget setting are checked on every request, even\nfor the owner. Responses are cross-origin readable and private, no-store.\nShares the live/realtime per-project and per-client rate limits. Hide the pill\non failure and honor Retry-After on 429 responses.",
        "tags": [
          "Dashboards"
        ],
        "security": [],
        "parameters": [
          {
            "name": "project",
            "in": "query",
            "required": false,
            "description": "The project's domain. Defaults to the deployment's own project.",
            "schema": {
              "$ref": "#/components/schemas/ProjectSlug"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The current count.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "online"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "online": {
                      "type": "integer",
                      "minimum": 0
                    }
                  }
                },
                "example": {
                  "online": 42
                }
              }
            }
          },
          "404": {
            "description": "The project does not publish realtime data, or does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: realtime_disabled."
                },
                "examples": {
                  "realtime_disabled": {
                    "$ref": "#/components/examples/error_realtime_disabled"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: rate_limited."
                },
                "examples": {
                  "rate_limited": {
                    "$ref": "#/components/examples/error_rate_limited"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Analytics are temporarily unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/realtime": {
      "get": {
        "operationId": "getRealtimeSnapshot",
        "summary": "Read a project's public live visitor count and activity feed",
        "description": "The number of people on a site right now. Cross-origin readable on purpose: it\nreturns exactly what an anonymous visitor already sees on the public dashboard, so a\nsite can print its own live count on its own pages.\n\nServed only for projects that publish it, from a shared cache whose lifetime equals\nthe poll interval. Past the per-project and per-client ceilings it answers 429 with a\n`Retry-After` — back off and keep showing the last good number rather than clearing it.",
        "tags": [
          "Dashboards"
        ],
        "security": [],
        "parameters": [
          {
            "name": "project",
            "in": "query",
            "required": false,
            "description": "The project's domain. Defaults to the deployment's own project.",
            "schema": {
              "$ref": "#/components/schemas/ProjectSlug"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The current snapshot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RealtimeSnapshot"
                },
                "example": {
                  "online": 42
                }
              }
            }
          },
          "404": {
            "description": "The project does not publish realtime data, or does not exist. Nothing to retry.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: realtime_disabled."
                },
                "examples": {
                  "realtime_disabled": {
                    "$ref": "#/components/examples/error_realtime_disabled"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: rate_limited."
                },
                "examples": {
                  "rate_limited": {
                    "$ref": "#/components/examples/error_rate_limited"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/live": {
      "get": {
        "operationId": "getLiveSnapshot",
        "summary": "Read a project's public live feed and visitor map",
        "description": "What the live row on a dashboard shows: the count, the recent events, and the\ncoordinates the globe plots. Gated widget by widget — if a project hides the stream,\nthis returns an empty `feed` rather than the data behind it.\n\nUnlike `getRealtimeSnapshot` this sends no CORS headers: a live count is something a\nsite displays on its own pages, a list of who is currently on it is not. It shares the\nrealtime rate-limit budget, so alternating between the two buys no extra allowance.",
        "tags": [
          "Dashboards"
        ],
        "security": [],
        "parameters": [
          {
            "name": "project",
            "in": "query",
            "required": false,
            "description": "The project's domain. Defaults to the deployment's own project.",
            "schema": {
              "$ref": "#/components/schemas/ProjectSlug"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The current snapshot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LiveSnapshot"
                },
                "example": {
                  "online": 42,
                  "feed": [],
                  "visitors": []
                }
              }
            }
          },
          "404": {
            "description": "The project has no published dashboard, or publishes neither half of the live row.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: dashboard_not_published, live_disabled."
                },
                "examples": {
                  "dashboard_not_published": {
                    "$ref": "#/components/examples/error_dashboard_not_published"
                  },
                  "live_disabled": {
                    "$ref": "#/components/examples/error_live_disabled"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: rate_limited."
                },
                "examples": {
                  "rate_limited": {
                    "$ref": "#/components/examples/error_rate_limited"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/projects": {
      "get": {
        "operationId": "listProjects",
        "summary": "List the projects you own",
        "description": "Your projects, never anybody else's. Authenticated with a session token from `analytiics login`, or with the browser's session cookie.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Your projects.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "projects"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "projects": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Project"
                      }
                    }
                  }
                },
                "example": {
                  "projects": [
                    {
                      "slug": "diiverge.co",
                      "name": "diiverge.co",
                      "createdAt": "2026-01-09T10:04:00.000Z",
                      "activeKeys": 1,
                      "publicDashboard": true
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET, POST.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET, POST"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "503": {
            "description": "The control plane was unreachable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createProject",
        "summary": "Create a project",
        "description": "A project is its domain. Whatever is sent is normalized to the one canonical form — lowercased, `www.` dropped, a pasted URL reduced to its host — and that is the value the tracker must send as `site` and the path the dashboard lives at. It is chosen once: every event is stored under it, so there is no rename.\n\nDomains are globally unique, so two people cannot both own `diiverge.co`. A domain someone else holds and one you already hold are both 409, with different messages.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "additionalProperties": false,
                "properties": {
                  "domain": {
                    "type": "string",
                    "description": "The site's domain. A URL, a `www.` host or mixed case are all accepted and normalized; a bare name (`app`) is not a domain and is refused.",
                    "examples": [
                      "diiverge.co",
                      "https://www.diiverge.co/"
                    ]
                  }
                }
              },
              "example": {
                "domain": "diiverge.co"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "project"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "project": {
                      "$ref": "#/components/schemas/Project"
                    }
                  }
                },
                "example": {
                  "project": {
                    "slug": "diiverge.co",
                    "name": "diiverge.co",
                    "createdAt": "2026-01-09T10:04:00.000Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The body was not JSON, or `domain` is not a domain.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: invalid_json, invalid_parameter."
                },
                "examples": {
                  "invalid_json": {
                    "$ref": "#/components/examples/error_invalid_json"
                  },
                  "invalid_parameter": {
                    "$ref": "#/components/examples/error_invalid_parameter"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "402": {
            "description": "The plan does not cover another project. Checked after the domain, so one somebody else holds is still a 409.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: plan_limit."
                },
                "examples": {
                  "plan_limit": {
                    "$ref": "#/components/examples/error_plan_limit"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET, POST.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET, POST"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "409": {
            "description": "That domain is taken.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: slug_taken."
                },
                "examples": {
                  "slug_taken": {
                    "$ref": "#/components/examples/error_slug_taken"
                  }
                }
              }
            }
          },
          "429": {
            "description": "More than twenty creates in an hour from one account.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: rate_limited."
                },
                "examples": {
                  "rate_limited": {
                    "$ref": "#/components/examples/error_rate_limited"
                  }
                }
              }
            }
          },
          "503": {
            "description": "The control plane was unreachable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/usage": {
      "get": {
        "operationId": "getUsage",
        "summary": "Read your plan and this month's usage",
        "description": "Account-wide, because a plan is: the cap is bought once and shared by every project you own. Billable events are page views plus the events you name yourself — the tracker's outbound-click and identify calls are not charged for. The period is the calendar month in UTC.\n\nCaps are soft: `level` reaching `approaching` or `over` is a notice, never a cut, and ingestion is not stopped mid-period.",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Your plan, and what this period has used of it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountUsage"
                },
                "example": {
                  "plan": {
                    "id": "free",
                    "name": "Free",
                    "priceCents": 0,
                    "events": 25000,
                    "projects": 1
                  },
                  "period": {
                    "startsAt": "2026-08-01T00:00:00.000Z",
                    "endsAt": "2026-09-01T00:00:00.000Z"
                  },
                  "events": 18402,
                  "level": "approaching",
                  "measured": true,
                  "sampled": false,
                  "projects": [
                    {
                      "slug": "diiverge.co",
                      "events": 18402
                    }
                  ],
                  "projectCount": 1
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "503": {
            "description": "The control plane was unreachable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/checkout": {
      "post": {
        "operationId": "createCheckout",
        "summary": "Start a checkout for a paid plan",
        "description": "Returns a Stripe URL: existing subscribers manage their subscription in the portal; new subscribers reuse an outstanding checkout. **It grants nothing.** The plan moves later, when Stripe reports that money moved — so the most this endpoint can produce is a link to a page where a person types a card number, and there is no request that grants a plan for a client to forge.\n\nThat is what makes it safe for an agent to call: it offers, a human buys. After sending someone to the URL, poll `getUsage` until `plan` changes rather than assuming the payment succeeded — this call's success means a link was minted, nothing more.\n\nA plan with no price configured on this deployment is a `400` naming the plans that do, not a `503`: no retry would make it work.",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "plan"
                ],
                "additionalProperties": false,
                "properties": {
                  "plan": {
                    "type": "string",
                    "enum": [
                      "maker",
                      "studio",
                      "scale"
                    ],
                    "description": "A paid plan this deployment sells. Free has nothing to buy."
                  }
                }
              },
              "example": {
                "plan": "maker"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "A checkout or billing portal session. Send a human to `url`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "url",
                    "plan"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "url": {
                      "type": "string",
                      "format": "uri",
                      "description": "Stripe's hosted checkout or billing portal page. Short-lived."
                    },
                    "plan": {
                      "type": "string",
                      "description": "The requested plan. Portal changes require confirmation there."
                    }
                  }
                },
                "example": {
                  "url": "https://checkout.stripe.com/c/pay/cs_test_…",
                  "plan": "maker"
                }
              }
            }
          },
          "400": {
            "description": "The body was not JSON, or `plan` did not name a plan this deployment sells.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: invalid_json, invalid_parameter."
                },
                "examples": {
                  "invalid_json": {
                    "$ref": "#/components/examples/error_invalid_json"
                  },
                  "invalid_parameter": {
                    "$ref": "#/components/examples/error_invalid_parameter"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts POST.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "POST"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "409": {
            "description": "Another checkout is in progress for this account.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: checkout_in_progress."
                },
                "examples": {
                  "checkout_in_progress": {
                    "$ref": "#/components/examples/error_checkout_in_progress"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Payments are not available here, so nothing was charged.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: billing_unavailable, unavailable."
                },
                "examples": {
                  "billing_unavailable": {
                    "$ref": "#/components/examples/error_billing_unavailable"
                  },
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/billing/portal": {
      "post": {
        "operationId": "createBillingPortalSession",
        "summary": "Open the billing portal",
        "description": "Returns a URL to Stripe's billing portal: invoices, the card on file, and cancelling. The customer comes from your session, so there is no parameter here that could point at another account.\n\nCancelling there produces the same subscription event as any other change, so a plan given up in the portal is taken away by the same path that granted it.",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "responses": {
          "201": {
            "description": "A portal session. Send a human to `url`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "url"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "url": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                },
                "example": {
                  "url": "https://billing.stripe.com/p/session/…"
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "404": {
            "description": "This account has never been billed, so there is nothing to manage.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: no_subscription."
                },
                "examples": {
                  "no_subscription": {
                    "$ref": "#/components/examples/error_no_subscription"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts POST.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "POST"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Payments are not available here.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: billing_unavailable, unavailable."
                },
                "examples": {
                  "billing_unavailable": {
                    "$ref": "#/components/examples/error_billing_unavailable"
                  },
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/projects/{slug}": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "description": "The project's domain.",
          "schema": {
            "$ref": "#/components/schemas/ProjectSlug"
          }
        }
      ],
      "get": {
        "operationId": "getProject",
        "summary": "Read one project you own",
        "description": "The project row itself — domain, name, timezone, age. What it publishes lives at `getDashboardVisibility`, and its keys at `listProjectKeys`.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "The project.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "project"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "project": {
                      "$ref": "#/components/schemas/Project"
                    }
                  }
                },
                "example": {
                  "project": {
                    "slug": "diiverge.co",
                    "name": "diiverge.co",
                    "timezone": "UTC",
                    "createdAt": "2026-01-09T10:04:00.000Z"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such project, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: project_not_found."
                },
                "examples": {
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET, DELETE.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET, DELETE"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "503": {
            "description": "The control plane was unreachable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteProject",
        "summary": "Delete a project",
        "description": "Removes the project, its write keys, its dashboard settings and every share link —\ningestion under its keys stops and snapshot URLs die with it.\n\nEvents already recorded are **not** purged from analytics storage. The dashboard\nand share links become unavailable, and the domain is permanently reserved so a\nnew project cannot inherit that history. Contact support for data deletion or recovery.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    }
                  }
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such project, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: project_not_found."
                },
                "examples": {
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET, DELETE.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET, DELETE"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "503": {
            "description": "The control plane was unreachable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/projects/{slug}/integrations/stripe": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "description": "The project domain.",
          "schema": {
            "$ref": "#/components/schemas/ProjectSlug"
          }
        }
      ],
      "get": {
        "operationId": "getStripeIntegration",
        "summary": "Read Stripe import and attribution status",
        "description": "Owner-only. Returns mode, last-four label, sync/backfill progress and confirmed payment counts. attributed_30d and latest_source are null when analytics verification is unavailable. No credential or encrypted key material is returned.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Stripe status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StripeIntegrationStatus"
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such project, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: project_not_found."
                },
                "examples": {
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET, POST, DELETE.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET, POST, DELETE"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "connectStripeIntegration",
        "summary": "Connect a restricted Stripe key",
        "description": "Owner-only. Accepts rk_test_ or rk_live_ keys; full secret keys are refused. Requires read access to Events, Charges, Refunds, Disputes, Checkout Sessions, Customers, Invoices/invoice payments and Subscriptions. Disable all write permissions in Stripe. Imports begin at the next scheduled sync. Disconnect before changing keys.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "key"
                ],
                "additionalProperties": false,
                "properties": {
                  "key": {
                    "type": "string",
                    "writeOnly": true,
                    "maxLength": 512,
                    "pattern": "^rk_(test|live)_[A-Za-z0-9]{8,}$"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Connected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StripeIntegrationStatus"
                }
              }
            }
          },
          "400": {
            "description": "Invalid restricted key or permissions.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: invalid_json, invalid_payload, invalid_parameter."
                },
                "examples": {
                  "invalid_json": {
                    "$ref": "#/components/examples/error_invalid_json"
                  },
                  "invalid_payload": {
                    "$ref": "#/components/examples/error_invalid_payload"
                  },
                  "invalid_parameter": {
                    "$ref": "#/components/examples/error_invalid_parameter"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such project, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: project_not_found."
                },
                "examples": {
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET, POST, DELETE.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET, POST, DELETE"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "409": {
            "description": "Already connected.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: integration_connected."
                },
                "examples": {
                  "integration_connected": {
                    "$ref": "#/components/examples/error_integration_connected"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "disconnectStripeIntegration",
        "summary": "Disconnect Stripe and revoke its delivery key",
        "description": "Owner-only. Deletes stored credentials and revokes the hidden integration delivery key. Imported revenue remains. Idempotent.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Disconnected.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "connected"
                  ],
                  "properties": {
                    "connected": {
                      "type": "boolean",
                      "const": false
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such project, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: project_not_found."
                },
                "examples": {
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET, POST, DELETE.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET, POST, DELETE"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/projects/{slug}/payments": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "description": "The project domain.",
          "schema": {
            "$ref": "#/components/schemas/ProjectSlug"
          }
        },
        {
          "name": "date_from",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Inclusive UTC timestamp, YYYY-MM-DD HH:mm:ss."
        },
        {
          "name": "date_to",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Exclusive UTC timestamp; at most 366 days after date_from."
        },
        {
          "name": "source",
          "in": "query",
          "description": "Exact first-touch source, including Unattributed.",
          "schema": {
            "type": "string",
            "maxLength": 200
          }
        },
        {
          "name": "channel",
          "in": "query",
          "description": "Exact first-touch channel.",
          "schema": {
            "type": "string",
            "maxLength": 100
          }
        }
      ],
      "get": {
        "operationId": "listProjectPayments",
        "summary": "List the latest 100 payments for an owner",
        "description": "Owner-only payment, refund and dispute rows with opaque user IDs and first-touch source attribution. Public revenue visibility never grants access to this endpoint. Source/channel filters are supported; other traffic filters do not narrow payments.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Payments.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "payments"
                  ],
                  "properties": {
                    "payments": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "event_id",
                          "timestamp",
                          "user_id",
                          "revenue_cents",
                          "currency",
                          "kind",
                          "source",
                          "channel",
                          "renewal"
                        ],
                        "properties": {
                          "event_id": {
                            "type": "string"
                          },
                          "timestamp": {
                            "type": "string"
                          },
                          "user_id": {
                            "type": "string"
                          },
                          "revenue_cents": {
                            "type": "integer"
                          },
                          "currency": {
                            "type": "string"
                          },
                          "kind": {
                            "type": "string"
                          },
                          "source": {
                            "type": "string"
                          },
                          "channel": {
                            "type": "string"
                          },
                          "renewal": {
                            "type": "integer",
                            "enum": [
                              0,
                              1
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid period.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: invalid_parameter."
                },
                "examples": {
                  "invalid_parameter": {
                    "$ref": "#/components/examples/error_invalid_parameter"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such project, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: project_not_found."
                },
                "examples": {
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Query capacity exhausted.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: rate_limited."
                },
                "examples": {
                  "rate_limited": {
                    "$ref": "#/components/examples/error_rate_limited"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/projects/{slug}/keys": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "description": "The project's domain.",
          "schema": {
            "$ref": "#/components/schemas/ProjectSlug"
          }
        }
      ],
      "get": {
        "operationId": "listProjectKeys",
        "summary": "List a project's write keys",
        "description": "By prefix and creation date. Key material is never returned — only a SHA-256 of a key is stored, so there is no way to read one again.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "The project's keys.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "keys"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "keys": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ApiKey"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such project — the same answer for a project you do not own, so this never confirms that a domain is taken.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: project_not_found."
                },
                "examples": {
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET, POST.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET, POST"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "503": {
            "description": "The control plane was unreachable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "issueProjectKey",
        "summary": "Issue a server write key",
        "description": "The response is the only time the key is readable. Store it server-side; a key in a browser bundle is a key you have to rotate. A leaked key can only write to the project it was issued for, and revoking one takes no redeploy. Supply an existing key to reuse it if it is active and belongs to this project; otherwise a new key is issued.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "existingKey": {
                    "type": "string",
                    "pattern": "^sk_live_[0-9a-f]{64}$",
                    "writeOnly": true,
                    "description": "An existing local write key. An active key for this project is reused without returning its plaintext."
                  },
                  "name": {
                    "type": "string",
                    "maxLength": 40,
                    "description": "A label, so a key listing means something later.",
                    "examples": [
                      "production"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Existing key reused. No key is created or returned.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "reused",
                    "prefix",
                    "id"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "reused": {
                      "type": "boolean",
                      "const": true
                    },
                    "prefix": {
                      "type": "string"
                    },
                    "id": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Issued. Read `key` now; it cannot be read again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IssuedKey"
                }
              }
            }
          },
          "400": {
            "description": "`name` or `existingKey` did not validate.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: invalid_json, invalid_parameter."
                },
                "examples": {
                  "invalid_json": {
                    "$ref": "#/components/examples/error_invalid_json"
                  },
                  "invalid_parameter": {
                    "$ref": "#/components/examples/error_invalid_parameter"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such project, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: project_not_found."
                },
                "examples": {
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET, POST.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET, POST"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "503": {
            "description": "The control plane was unreachable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/projects/{slug}/keys/{id}": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "description": "The project's domain.",
          "schema": {
            "$ref": "#/components/schemas/ProjectSlug"
          }
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "The key's id, from `listProjectKeys` or `issueProjectKey`.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "delete": {
        "operationId": "revokeProjectKey",
        "summary": "Revoke a write key",
        "description": "The key stops authorizing writes immediately; no redeploy is involved. Revocation is a tombstone rather than a delete — the key stays in `listProjectKeys` with `revoked: true`, so the listing can show when a key died as well as that it did. Revoking twice is not an error: the second call reports `alreadyRevoked: true` and the tombstone's date does not move.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked — or already was.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "key",
                    "alreadyRevoked"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "key": {
                      "$ref": "#/components/schemas/ApiKey"
                    },
                    "alreadyRevoked": {
                      "type": "boolean",
                      "description": "True when the key was dead before this call."
                    }
                  }
                },
                "example": {
                  "key": {
                    "id": "5f2c…",
                    "name": "production",
                    "prefix": "sk_live_9f2c…",
                    "createdAt": "2026-01-09T10:04:00.000Z",
                    "lastUsedAt": null,
                    "revoked": true
                  },
                  "alreadyRevoked": false
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such key on this project, or no such project. A key belonging to another project gets the same answer as one that never existed.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: key_not_found, project_not_found."
                },
                "examples": {
                  "key_not_found": {
                    "$ref": "#/components/examples/error_key_not_found"
                  },
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts DELETE.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "DELETE"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "503": {
            "description": "The control plane was unreachable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/projects/{slug}/journeys": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "description": "The project domain or legacy project slug.",
          "schema": {
            "$ref": "#/components/schemas/ProjectSlug"
          }
        }
      ],
      "get": {
        "operationId": "getPersonJourney",
        "summary": "Read one person’s activity and sessions",
        "description": "Owner-only. Authorization precedes cached analytics. No public widget grants access. Responses use private, no-store. Unknown projects and non-owners receive the same 404.",
        "tags": [
          "Dashboards"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "parameters": [
          {
            "name": "person",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^(user|visitor):.{1,256}$"
            },
            "description": "Exact opaque user id or current-day anonymous id with the indicated prefix."
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 4096
            },
            "description": "Cursor from next; never invent or modify."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 200
            },
            "description": "Maximum events per page (1–500)."
          }
        ],
        "responses": {
          "200": {
            "description": "Owner-only analytics.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "person",
                    "day",
                    "events",
                    "sessions",
                    "summary",
                    "next"
                  ],
                  "properties": {
                    "person": {
                      "type": "string"
                    },
                    "day": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Current UTC date for visitors; null for identified users."
                    },
                    "events": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "timestamp": {
                            "type": "string"
                          },
                          "sort_key": {
                            "type": "string"
                          },
                          "event_name": {
                            "type": "string"
                          },
                          "user_id": {
                            "type": "string"
                          },
                          "path": {
                            "type": "string"
                          },
                          "referrer": {
                            "type": "string"
                          },
                          "source": {
                            "type": "string"
                          },
                          "channel": {
                            "type": "string"
                          },
                          "device": {
                            "type": "string"
                          },
                          "browser": {
                            "type": "string"
                          },
                          "os": {
                            "type": "string"
                          },
                          "country": {
                            "type": "string"
                          },
                          "city": {
                            "type": "string"
                          },
                          "session_id": {
                            "type": "string"
                          },
                          "currency": {
                            "type": "string"
                          },
                          "sdk": {
                            "type": "string"
                          },
                          "props": {
                            "type": "object",
                            "additionalProperties": true
                          },
                          "revenue_cents": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "sessions": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "session_id": {
                            "type": "string"
                          },
                          "started": {
                            "type": "string"
                          },
                          "ended": {
                            "type": "string"
                          },
                          "entry_path": {
                            "type": "string"
                          },
                          "exit_path": {
                            "type": "string"
                          },
                          "entry_source": {
                            "type": "string"
                          },
                          "entry_channel": {
                            "type": "string"
                          },
                          "pageviews": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "summary": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "properties": {
                        "first_seen": {
                          "type": "string"
                        },
                        "last_seen": {
                          "type": "string"
                        },
                        "first_source": {
                          "type": "string"
                        },
                        "first_channel": {
                          "type": "string"
                        },
                        "country": {
                          "type": "string"
                        },
                        "device": {
                          "type": "string"
                        },
                        "server_only": {
                          "type": "boolean"
                        },
                        "revenue": {
                          "type": "array",
                          "items": {
                            "type": "array",
                            "prefixItems": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "integer"
                              }
                            ],
                            "items": false,
                            "minItems": 2,
                            "maxItems": 2
                          }
                        }
                      }
                    },
                    "next": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Opaque signed cursor. Pass unchanged as before for the same project/person. Visitor cursors expire at UTC midnight."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters or expired cursor.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: invalid_parameter."
                },
                "examples": {
                  "invalid_parameter": {
                    "$ref": "#/components/examples/error_invalid_parameter"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Project missing or caller is not its owner.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: project_not_found."
                },
                "examples": {
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Query allowance exhausted; wait for Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: rate_limited."
                },
                "examples": {
                  "rate_limited": {
                    "$ref": "#/components/examples/error_rate_limited"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Analytics unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/projects/{slug}/people": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "description": "The project domain or legacy project slug.",
          "schema": {
            "$ref": "#/components/schemas/ProjectSlug"
          }
        }
      ],
      "get": {
        "operationId": "getPeople",
        "summary": "Find recent identified users",
        "description": "Owner-only. Authorization precedes cached analytics. No public widget grants access. Responses use private, no-store. Unknown projects and non-owners receive the same 404.",
        "tags": [
          "Dashboards"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "parameters": [
          {
            "name": "range",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "today",
                "yesterday",
                "6h",
                "12h",
                "24h",
                "48h",
                "72h",
                "7d",
                "14d",
                "30d",
                "90d",
                "365d",
                "3mo",
                "6mo",
                "12mo",
                "custom"
              ]
            },
            "description": "Project reporting period in its configured timezone."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Required with range=custom. Inclusive start date in the project timezone, on or after 1970-01-01."
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Required with range=custom. Inclusive end date, no later than today in the project timezone. The range may span up to 366 days."
          },
          {
            "name": "user_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 256
            },
            "description": "Exact opaque user id; no email search."
          },
          {
            "name": "event",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128
            },
            "description": "People who did this event in the period. Counts cover their full activity in that period."
          }
        ],
        "responses": {
          "200": {
            "description": "Owner-only analytics.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "people"
                  ],
                  "properties": {
                    "people": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "user_id": {
                            "type": "string"
                          },
                          "first_seen": {
                            "type": "string"
                          },
                          "first_source": {
                            "type": "string"
                          },
                          "first_channel": {
                            "type": "string"
                          },
                          "last_seen": {
                            "type": "string"
                          },
                          "sessions": {
                            "type": "integer"
                          },
                          "events": {
                            "type": "integer"
                          },
                          "revenue": {
                            "type": "array",
                            "items": {
                              "type": "array",
                              "prefixItems": [
                                {
                                  "type": "string"
                                },
                                {
                                  "type": "integer"
                                }
                              ],
                              "items": false,
                              "minItems": 2,
                              "maxItems": 2
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters or expired cursor.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: invalid_parameter."
                },
                "examples": {
                  "invalid_parameter": {
                    "$ref": "#/components/examples/error_invalid_parameter"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Project missing or caller is not its owner.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: project_not_found."
                },
                "examples": {
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Query allowance exhausted; wait for Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: rate_limited."
                },
                "examples": {
                  "rate_limited": {
                    "$ref": "#/components/examples/error_rate_limited"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Analytics unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/projects/{slug}/dashboard": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "description": "The project's domain.",
          "schema": {
            "$ref": "#/components/schemas/ProjectSlug"
          }
        }
      ],
      "get": {
        "operationId": "getDashboardVisibility",
        "summary": "Read what a project publishes",
        "description": "`widgets` is sparse — what has been decided, not what it adds up to. `defaults` is what an absent key means, so a caller can render the difference.",
        "tags": [
          "Dashboards"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "The project's publication settings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DashboardVisibility"
                },
                "example": {
                  "published": true,
                  "widgets": {
                    "revenue": true
                  },
                  "defaults": {
                    "revenue": false
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such project, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: project_not_found."
                },
                "examples": {
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET, PATCH.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET, PATCH"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "503": {
            "description": "The control plane was unreachable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateDashboardVisibility",
        "summary": "Change what an anonymous reader sees",
        "description": "Merges: sending one widget leaves the rest alone. `null` clears an override, which is how a widget goes back to its default. An unknown widget key is a 400 rather than a silent no-op — storing a typo would leave someone certain they had hidden a card that is still on the page.",
        "tags": [
          "Dashboards"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "published": {
                    "type": "boolean",
                    "description": "Whether anyone but the owner may see the dashboard at all."
                  },
                  "widgets": {
                    "type": "object",
                    "additionalProperties": {
                      "type": [
                        "boolean",
                        "null"
                      ]
                    },
                    "description": "Per-widget overrides. `null` clears one."
                  },
                  "timezone": {
                    "type": "string",
                    "description": "IANA zone name, like \"America/New_York\". Sets whose days the dashboard's day windows are — an unresolvable name is a 400."
                  },
                  "defaultRange": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "The window the dashboard opens on when its URL names none, as a range token the picker offers (\"24h\", \"7d\", \"today\"). `null` hands it back to the app's default; a token the picker does not offer is a 400."
                  }
                }
              },
              "example": {
                "published": true,
                "widgets": {
                  "revenue": false
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The settings as they now stand.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DashboardVisibility"
                }
              }
            }
          },
          "400": {
            "description": "The body was not JSON, or named a widget that does not exist. The message lists the widgets that do.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: invalid_json, invalid_parameter."
                },
                "examples": {
                  "invalid_json": {
                    "$ref": "#/components/examples/error_invalid_json"
                  },
                  "invalid_parameter": {
                    "$ref": "#/components/examples/error_invalid_parameter"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such project, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: project_not_found."
                },
                "examples": {
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET, PATCH.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET, PATCH"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "503": {
            "description": "The control plane was unreachable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/projects/{slug}/manifest": {
      "parameters": [
        {
          "name": "slug",
          "in": "path",
          "required": true,
          "description": "The project's domain.",
          "schema": {
            "$ref": "#/components/schemas/ProjectSlug"
          }
        }
      ],
      "get": {
        "operationId": "getManifest",
        "summary": "Read the project's tracking manifest",
        "description": "A project that has never uploaded one gets nulls and a 200, not a 404 — no manifest is an ordinary state, since web analytics derives nothing from it.",
        "tags": [
          "Dashboards"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "The stored manifest, or nulls.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoredManifest"
                },
                "example": {
                  "manifest": null,
                  "hash": null,
                  "updated_at": null
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such project, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: project_not_found."
                },
                "examples": {
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET, PUT, DELETE.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET, PUT, DELETE"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "503": {
            "description": "The control plane was unreachable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "putManifest",
        "summary": "Upload analytics.yaml",
        "description": "Takes the YAML **source**, not a parsed document. The server runs the same parser `analytiics validate` runs, so the two cannot disagree about what a manifest means and a caller cannot store something that would have failed validation by parsing it themselves first. The hash is computed here for the same reason.\n\nReplaces wholesale rather than merging: a manifest is one document, and a merged one would still declare an event the customer deleted. A manifest whose `project` is not this project's domain is refused — that is how a second repository would otherwise overwrite the first one's tracking plan.",
        "tags": [
          "Dashboards"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "manifest"
                ],
                "additionalProperties": false,
                "properties": {
                  "manifest": {
                    "type": "string",
                    "description": "The contents of analytics.yaml. At most 256 KiB."
                  }
                }
              },
              "example": {
                "manifest": "version: 1\nproject: thiings\nevents:\n  page_published:\n    description: User published their page\n"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The manifest as stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoredManifest"
                }
              }
            }
          },
          "400": {
            "description": "The body was not JSON, the manifest did not validate, or it names a different project. The message carries the same lines `analytiics validate` prints.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: invalid_json, invalid_parameter, invalid_payload."
                },
                "examples": {
                  "invalid_json": {
                    "$ref": "#/components/examples/error_invalid_json"
                  },
                  "invalid_parameter": {
                    "$ref": "#/components/examples/error_invalid_parameter"
                  },
                  "invalid_payload": {
                    "$ref": "#/components/examples/error_invalid_payload"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such project, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: project_not_found."
                },
                "examples": {
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET, PUT, DELETE.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET, PUT, DELETE"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "503": {
            "description": "The control plane was unreachable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteManifest",
        "summary": "Forget the project's manifest",
        "description": "Takes the derived sections off the dashboard. Recorded events stay in the analytics store — they happened — so this is the project ceasing to declare a tracking plan, which is what removing the file from the repository means. Idempotent.",
        "tags": [
          "Dashboards"
        ],
        "security": [
          {
            "sessionToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Forgotten.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoredManifest"
                },
                "example": {
                  "manifest": null,
                  "hash": null,
                  "updated_at": null
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unauthorized."
                },
                "examples": {
                  "unauthorized": {
                    "$ref": "#/components/examples/error_unauthorized"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such project, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: project_not_found."
                },
                "examples": {
                  "project_not_found": {
                    "$ref": "#/components/examples/error_project_not_found"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts GET, PUT, DELETE.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "GET, PUT, DELETE"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "503": {
            "description": "The control plane was unreachable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/waitlist": {
      "post": {
        "operationId": "joinWaitlist",
        "summary": "Join the private beta waitlist",
        "description": "Public. Answers the same way whether the address was new or already on the list — \"you are already on it\" would make this a way to ask whether a given person signed up.",
        "tags": [
          "Meta"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "additionalProperties": false,
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "source": {
                    "type": "string",
                    "description": "Where the signup came from, for our own attribution.",
                    "examples": [
                      "waitlist-footer"
                    ]
                  }
                }
              },
              "example": {
                "email": "you@example.com",
                "source": "hero"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Recorded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    }
                  }
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "description": "The body was not JSON, or the address did not look like one.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: invalid_json, invalid_parameter."
                },
                "examples": {
                  "invalid_json": {
                    "$ref": "#/components/examples/error_invalid_json"
                  },
                  "invalid_parameter": {
                    "$ref": "#/components/examples/error_invalid_parameter"
                  }
                }
              }
            }
          },
          "405": {
            "description": "The path exists but does not accept this method. It accepts POST.",
            "headers": {
              "Allow": {
                "description": "The methods this path accepts.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "POST"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: method_not_allowed."
                },
                "examples": {
                  "method_not_allowed": {
                    "$ref": "#/components/examples/error_method_not_allowed"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: rate_limited."
                },
                "examples": {
                  "rate_limited": {
                    "$ref": "#/components/examples/error_rate_limited"
                  }
                }
              }
            }
          },
          "503": {
            "description": "The waitlist store was unreachable.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ],
                  "description": "`code` is one of: unavailable."
                },
                "examples": {
                  "unavailable": {
                    "$ref": "#/components/examples/error_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "StripeIntegrationStatus": {
        "description": "Owner-only connection metadata and import progress. No key material is returned. Attribution fields are null when analytics verification is unavailable.",
        "type": "object",
        "required": [
          "connected"
        ],
        "additionalProperties": false,
        "properties": {
          "connected": {
            "type": "boolean"
          },
          "mode": {
            "type": "string",
            "enum": [
              "test",
              "live"
            ]
          },
          "label": {
            "type": "string"
          },
          "last_synced_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "last_error": {
            "type": [
              "string",
              "null"
            ]
          },
          "payments_imported": {
            "type": "integer"
          },
          "payments_30d": {
            "type": "integer"
          },
          "linked_30d": {
            "type": "integer"
          },
          "attributed_30d": {
            "type": [
              "integer",
              "null"
            ]
          },
          "latest_source": {
            "type": [
              "string",
              "null"
            ]
          },
          "backfill": {
            "type": "object",
            "properties": {
              "complete": {
                "type": "boolean"
              },
              "capped": {
                "type": "boolean"
              },
              "charges_scanned": {
                "type": "integer"
              },
              "through": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "title": "Error",
        "description": "The body of every Analytiics API failure, on both hosts. Switch on `code`: it is stable, it maps to exactly one HTTP status, and unlike the sentence it will not be reworded. `error` and `message` carry the same sentence — `error` is the field existing Analytiics clients read, `message` the one generic clients look for.",
        "required": [
          "error",
          "code",
          "message",
          "hint",
          "docs"
        ],
        "additionalProperties": false,
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable explanation. Same string as `message`.",
            "examples": [
              "no such project"
            ]
          },
          "code": {
            "type": "string",
            "enum": [
              "integration_connected",
              "invalid_json",
              "invalid_payload",
              "invalid_parameter",
              "unauthorized",
              "not_found",
              "project_not_found",
              "site_mismatch",
              "key_not_found",
              "realtime_disabled",
              "live_disabled",
              "dashboard_not_published",
              "slug_taken",
              "plan_limit",
              "billing_unavailable",
              "checkout_in_progress",
              "event_conflict",
              "no_subscription",
              "rate_limited",
              "unavailable",
              "key_verification_unavailable",
              "method_not_allowed"
            ],
            "description": "Stable machine-readable failure code.",
            "examples": [
              "project_not_found"
            ]
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation. Same string as `error`.",
            "examples": [
              "no such project"
            ]
          },
          "hint": {
            "type": "string",
            "description": "What to change, or wait for, to get a different answer."
          },
          "docs": {
            "type": "string",
            "format": "uri",
            "description": "Where this endpoint and its failures are documented.",
            "examples": [
              "https://www.analytiics.co/docs/api"
            ]
          },
          "detail": {
            "type": "string",
            "description": "The first validation failure, when the request was rejected for its shape. Absent otherwise."
          }
        }
      },
      "BrowserEvent": {
        "type": "object",
        "title": "BrowserEvent",
        "description": "One event from a browser. Location and device are derived from the request headers, so nothing about the visitor's IP is stored and none of it belongs in this body.",
        "required": [
          "site",
          "name",
          "url"
        ],
        "additionalProperties": false,
        "properties": {
          "site": {
            "$ref": "#/components/schemas/ProjectSlug"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "description": "The event name, as declared in analytics.yaml. Names starting with `$` are reserved.",
            "examples": [
              "page_view",
              "page_published"
            ]
          },
          "url": {
            "type": "string",
            "maxLength": 2048,
            "description": "The page URL. UTM parameters are read from it.",
            "examples": [
              "https://example.com/editor?utm_source=hn"
            ]
          },
          "ref": {
            "type": "string",
            "maxLength": 2048,
            "default": "",
            "description": "The referrer. Self-referrals are not counted as referral traffic, but are still stored.",
            "examples": [
              "https://news.ycombinator.com/"
            ]
          },
          "sid": {
            "type": "string",
            "maxLength": 64,
            "default": "",
            "description": "The tracker's session id."
          },
          "uid": {
            "type": "string",
            "maxLength": 128,
            "default": "",
            "description": "The known user id, set by `tracker.identify()`. This is the join key that later lets a server-side sale find the visit that earned it."
          },
          "ts": {
            "type": "string",
            "format": "date-time",
            "description": "When the event happened. Defaults to arrival. Clamped to now if more than 7 days in the past or 5 minutes in the future — browser clocks lie."
          },
          "props": {
            "type": "object",
            "additionalProperties": true,
            "description": "Event properties. Declared in analytics.yaml and typed at the call site. Never put personal data here — no emails, names, addresses or user-authored text. Serialised props are truncated at 8192 bytes.",
            "examples": [
              {
                "template": "grid",
                "link_count": 12
              }
            ]
          }
        }
      },
      "ServerEvent": {
        "type": "object",
        "title": "ServerEvent",
        "description": "One event from your backend. This is the only path that may carry money; browser identify calls also carry identity.",
        "required": [
          "name",
          "event_id"
        ],
        "additionalProperties": false,
        "properties": {
          "event_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "description": "Project-scoped logical event ID. Reuse for retries; use the payment provider event ID for webhook replays. Conflicting reuse returns 409. The first delivery fixes its timestamp.",
            "examples": [
              "evt_provider_123"
            ]
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "description": "The event name, as declared in analytics.yaml. Names starting with $ are reserved, except $identify.",
            "examples": [
              "subscription_started"
            ]
          },
          "user_id": {
            "type": "string",
            "maxLength": 128,
            "default": "",
            "description": "The user this event belongs to — the same id passed to `identify()` in the browser. Without it a sale cannot be attributed to the visit that earned it.",
            "examples": [
              "usr_123"
            ]
          },
          "anonymous_id": {
            "type": "string",
            "maxLength": 64,
            "default": "",
            "description": "The visitor id, when your backend captured it. Left empty on purpose otherwise: a synthetic one would count every webhook as an extra visitor."
          },
          "session_id": {
            "type": "string",
            "maxLength": 64,
            "default": ""
          },
          "url": {
            "type": "string",
            "maxLength": 2048,
            "default": ""
          },
          "revenue_cents": {
            "type": "integer",
            "minimum": -1000000000000,
            "maximum": 1000000000000,
            "description": "Money, in the minor unit of `currency`. Signed: refunds and chargebacks are ordinary events with a negative amount. Requires `currency`.",
            "examples": [
              2900
            ]
          },
          "currency": {
            "type": "string",
            "pattern": "^[A-Za-z]{3}$",
            "description": "ISO 4217, three letters. Required whenever `revenue_cents` is set — an amount with no unit cannot be summed, and defaulting to USD would misreport every other customer. Revenue is grouped by currency and never summed across currencies.",
            "examples": [
              "USD"
            ]
          },
          "ts": {
            "type": "string",
            "format": "date-time",
            "description": "When the event happened. Defaults to arrival. Accepted up to 30 days in the past, because webhook providers retry for days."
          },
          "props": {
            "type": "object",
            "additionalProperties": true,
            "description": "Event properties. Declared in analytics.yaml and typed at the call site. Never put personal data here — no emails, names, addresses or user-authored text. Serialised props are truncated at 8192 bytes.",
            "examples": [
              {
                "template": "grid",
                "link_count": 12
              }
            ]
          }
        },
        "dependentRequired": {
          "revenue_cents": [
            "currency"
          ]
        }
      },
      "ProjectSlug": {
        "type": "string",
        "minLength": 1,
        "maxLength": 64,
        "pattern": "^[a-z0-9][a-z0-9_-]*(?:\\.[a-z0-9][a-z0-9_-]*)*$",
        "description": "A project's identifier: its domain, lowercase, without `www.` — `diiverge.co`, `app.diiverge.co`. Globally unique, because it is what the tracker sends as `site`. Projects created before domains became the rule keep the bare name (`thiings`) their events were recorded under.",
        "examples": [
          "diiverge.co",
          "thiings"
        ]
      },
      "Accepted": {
        "type": "object",
        "title": "Accepted",
        "description": "How many rows were written.",
        "required": [
          "accepted"
        ],
        "additionalProperties": false,
        "properties": {
          "accepted": {
            "type": "integer",
            "minimum": 0,
            "description": "Rows written. `0` with a 202 means the traffic was identified as a bot and dropped, which is not an error and must not be retried."
          }
        }
      },
      "Plan": {
        "type": "object",
        "title": "Plan",
        "description": "What an account's plan allows. A plan is bought once and shared by every project the account owns — there is no per-project allowance.",
        "required": [
          "id",
          "name",
          "priceCents",
          "events",
          "projects"
        ],
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "enum": [
              "free",
              "maker",
              "studio",
              "scale"
            ]
          },
          "name": {
            "type": "string",
            "description": "What the plan is called on a bill."
          },
          "priceCents": {
            "type": "integer",
            "minimum": 0,
            "description": "Monthly price, in US cents."
          },
          "events": {
            "type": "integer",
            "minimum": 0,
            "description": "Billable events per calendar month. A page view and the events you name yourself count; the tracker's own outbound-click and identify calls do not."
          },
          "projects": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Projects the account may own at once. `null` means no ceiling."
          }
        }
      },
      "AccountUsage": {
        "type": "object",
        "title": "AccountUsage",
        "description": "What the account has spent of its plan this billing period. `measured: false` means the analytics store could not be counted, and `events` is then `null` rather than zero — an uncounted month is not a month of no usage.",
        "required": [
          "plan",
          "period",
          "events",
          "level",
          "measured",
          "sampled",
          "projects",
          "projectCount"
        ],
        "additionalProperties": false,
        "properties": {
          "plan": {
            "$ref": "#/components/schemas/Plan"
          },
          "period": {
            "type": "object",
            "description": "The billing period: the calendar month in **UTC**, half-open. One clock rather than each project's own timezone, because an account can own projects in several and a total of overlapping months is not a total.",
            "required": [
              "startsAt",
              "endsAt"
            ],
            "additionalProperties": false,
            "properties": {
              "startsAt": {
                "type": "string",
                "format": "date-time"
              },
              "endsAt": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "events": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Billable events this period, or `null` when they could not be counted."
          },
          "level": {
            "type": "string",
            "enum": [
              "ok",
              "approaching",
              "over"
            ],
            "description": "Where the account stands. `approaching` from 80% of the cap, `over` from 100%. Neither stops ingestion: caps are soft, and nothing is cut mid-period."
          },
          "measured": {
            "type": "boolean",
            "description": "Whether `events` was actually counted."
          },
          "sampled": {
            "type": "boolean",
            "description": "Whether the collector is currently keeping one browser event in ten for this account — the state past `over`, decided by the hourly usage sweep. Server events are never sampled. Clears when the month resets or the plan grows."
          },
          "projects": {
            "type": "array",
            "description": "The same count, per project, so a full month can be attributed.",
            "items": {
              "type": "object",
              "required": [
                "slug",
                "events"
              ],
              "additionalProperties": false,
              "properties": {
                "slug": {
                  "$ref": "#/components/schemas/ProjectSlug"
                },
                "events": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "minimum": 0
                }
              }
            }
          },
          "projectCount": {
            "type": "integer",
            "minimum": 0,
            "description": "How many projects the account owns, against `plan.projects`."
          }
        }
      },
      "Project": {
        "type": "object",
        "title": "Project",
        "description": "A project: one domain, one dashboard, one set of write keys. Events are partitioned by project, and a write key authorizes exactly one of them.",
        "required": [
          "slug",
          "name",
          "createdAt"
        ],
        "additionalProperties": false,
        "properties": {
          "slug": {
            "$ref": "#/components/schemas/ProjectSlug"
          },
          "name": {
            "type": "string",
            "maxLength": 80,
            "description": "What the project is called on screen: its domain. Projects created before domains became the rule may carry the display name they were given then."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "timezone": {
            "type": "string",
            "description": "IANA zone name — the project's calendar. Returned by `getProject`; set it through `updateDashboardVisibility`.",
            "examples": [
              "America/New_York"
            ]
          },
          "activeKeys": {
            "type": "integer",
            "minimum": 0,
            "description": "How many write keys still authorize writes to this project."
          },
          "publicDashboard": {
            "type": "boolean",
            "description": "Whether https://www.analytiics.co/p/{slug} is readable without an account."
          }
        }
      },
      "ApiKey": {
        "type": "object",
        "title": "ApiKey",
        "description": "A server write key, by prefix. Key material is never returned by a listing.",
        "required": [
          "id",
          "prefix",
          "createdAt",
          "revoked"
        ],
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "maxLength": 40,
            "description": "What it was labelled when issued."
          },
          "prefix": {
            "type": "string",
            "description": "The leading characters, which is how a key is identified after issue.",
            "examples": [
              "sk_live_9f2c"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastUsedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Null if it has never authorized a write."
          },
          "revoked": {
            "type": "boolean"
          }
        }
      },
      "IssuedKey": {
        "type": "object",
        "title": "IssuedKey",
        "description": "The one and only time a key's plaintext exists outside your hands. Only a SHA-256 of it is stored, so there is no way to read it again — losing it means issuing another and revoking this one.",
        "required": [
          "key",
          "prefix",
          "id"
        ],
        "additionalProperties": false,
        "properties": {
          "key": {
            "type": "string",
            "description": "The write key. Store it server-side; never ship it to a browser.",
            "examples": [
              "sk_live_9f2c…"
            ]
          },
          "prefix": {
            "type": "string"
          },
          "id": {
            "type": "string"
          }
        }
      },
      "StoredManifest": {
        "type": "object",
        "title": "StoredManifest",
        "description": "The project's copy of `analytics.yaml`, as the CLI last uploaded it. A copy, not the source of truth — the file in the repository is that, and this is downstream of it. Every field is null for a project that has never uploaded one, which is an ordinary state rather than an error: web analytics needs no manifest at all.",
        "required": [
          "manifest",
          "hash",
          "updated_at"
        ],
        "additionalProperties": true,
        "properties": {
          "manifest": {
            "type": [
              "object",
              "null"
            ],
            "description": "The parsed document: `version`, `project`, `events`, optional `integrations: [stripe]`, and a `dashboards` block. Its shape is the manifest schema, documented at /docs/manifest."
          },
          "hash": {
            "type": [
              "string",
              "null"
            ],
            "description": "Short digest of the parsed document — the same value codegen writes into `analytics.gen.ts` as `MANIFEST_HASH` and the SDK stamps on events as `manifest_version`. Computed here rather than accepted from the caller.",
            "examples": [
              "9f2c1ab4de77c001"
            ]
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "events": {
            "type": "integer",
            "description": "How many events the stored manifest declares. Present on upload only."
          }
        }
      },
      "DashboardVisibility": {
        "type": "object",
        "title": "DashboardVisibility",
        "description": "What a project publishes. `published` decides whether anyone but the owner may see the dashboard at all; `widgets` decides how much of it they see when they do; `timezone` is the project's calendar — the lens every viewer's \"today\" is assembled through; `defaultRange` is the window the dashboard opens on when its URL names none.",
        "required": [
          "published",
          "widgets",
          "defaults",
          "timezone",
          "defaultRange",
          "defaultRangeFallback"
        ],
        "additionalProperties": false,
        "properties": {
          "published": {
            "type": "boolean"
          },
          "timezone": {
            "type": "string",
            "description": "IANA zone name. Days on this dashboard are this zone's days.",
            "examples": [
              "America/New_York"
            ]
          },
          "defaultRange": {
            "type": [
              "string",
              "null"
            ],
            "description": "A range token as the dashboard's picker offers them (\"24h\", \"7d\", \"today\"). Sparse like `widgets`: `null` means the app's default, named in `defaultRangeFallback`.",
            "examples": [
              "7d"
            ]
          },
          "defaultRangeFallback": {
            "type": "string",
            "description": "What a null `defaultRange` means.",
            "examples": [
              "24h"
            ]
          },
          "widgets": {
            "type": "object",
            "additionalProperties": {
              "type": [
                "boolean",
                "null"
              ]
            },
            "description": "Sparse: what has been decided, not what it adds up to. An absent key means the default in `defaults`; `null` clears an override."
          },
          "defaults": {
            "type": "object",
            "additionalProperties": {
              "type": "boolean"
            },
            "description": "What an absent key means, so a caller can render the difference."
          }
        }
      },
      "RealtimeSnapshot": {
        "type": "object",
        "title": "RealtimeSnapshot",
        "description": "Exactly what an anonymous visitor already sees on https://www.analytiics.co/p/{slug}.",
        "required": [
          "online"
        ],
        "properties": {
          "online": {
            "type": "integer",
            "minimum": 0,
            "description": "People on the site in the last five minutes."
          }
        },
        "additionalProperties": true
      },
      "LiveSnapshot": {
        "type": "object",
        "title": "LiveSnapshot",
        "description": "The live row behind a dashboard: the number over it, the recent events, and the coordinates the globe plots. Halves are withheld individually — a project can publish the stream without the map, or the map without the stream.",
        "required": [
          "online"
        ],
        "properties": {
          "online": {
            "type": "integer",
            "minimum": 0
          },
          "feed": {
            "type": "array",
            "description": "Recent events. Empty when the project does not publish the stream.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "visitors": {
            "type": "array",
            "description": "Coordinates for the globe. Empty when the project does not publish the map.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        },
        "additionalProperties": true
      },
      "Health": {
        "type": "object",
        "title": "Health",
        "required": [
          "ok"
        ],
        "additionalProperties": false,
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          }
        },
        "description": "Liveness of the collector at https://in.analytiics.co."
      }
    },
    "securitySchemes": {
      "writeKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "A project write key, `sk_live_…`, sent as `Authorization: Bearer <key>`. Authorizes writes to exactly one project. Shown once, when issued; only its hash is stored. Keep it server-side."
      },
      "sessionToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "A session token, obtained by `analytiics login` through the OAuth device flow and sent as `Authorization: Bearer <token>`. Authorizes the management endpoints as the person who signed in. Browsers send the same session as a cookie instead."
      }
    },
    "examples": {
      "error_integration_connected": {
        "summary": "integration_connected",
        "value": {
          "error": "…",
          "code": "integration_connected",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_invalid_json": {
        "summary": "invalid_json",
        "value": {
          "error": "…",
          "code": "invalid_json",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_invalid_payload": {
        "summary": "invalid_payload",
        "value": {
          "error": "…",
          "code": "invalid_payload",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_invalid_parameter": {
        "summary": "invalid_parameter",
        "value": {
          "error": "…",
          "code": "invalid_parameter",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_unauthorized": {
        "summary": "unauthorized",
        "value": {
          "error": "…",
          "code": "unauthorized",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_not_found": {
        "summary": "not_found",
        "value": {
          "error": "…",
          "code": "not_found",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_project_not_found": {
        "summary": "project_not_found",
        "value": {
          "error": "…",
          "code": "project_not_found",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_site_mismatch": {
        "summary": "site_mismatch",
        "value": {
          "error": "…",
          "code": "site_mismatch",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_key_not_found": {
        "summary": "key_not_found",
        "value": {
          "error": "…",
          "code": "key_not_found",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_realtime_disabled": {
        "summary": "realtime_disabled",
        "value": {
          "error": "…",
          "code": "realtime_disabled",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_live_disabled": {
        "summary": "live_disabled",
        "value": {
          "error": "…",
          "code": "live_disabled",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_dashboard_not_published": {
        "summary": "dashboard_not_published",
        "value": {
          "error": "…",
          "code": "dashboard_not_published",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_slug_taken": {
        "summary": "slug_taken",
        "value": {
          "error": "…",
          "code": "slug_taken",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_plan_limit": {
        "summary": "plan_limit",
        "value": {
          "error": "…",
          "code": "plan_limit",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_billing_unavailable": {
        "summary": "billing_unavailable",
        "value": {
          "error": "…",
          "code": "billing_unavailable",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_checkout_in_progress": {
        "summary": "checkout_in_progress",
        "value": {
          "error": "…",
          "code": "checkout_in_progress",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_event_conflict": {
        "summary": "event_conflict",
        "value": {
          "error": "…",
          "code": "event_conflict",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_no_subscription": {
        "summary": "no_subscription",
        "value": {
          "error": "…",
          "code": "no_subscription",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_rate_limited": {
        "summary": "rate_limited",
        "value": {
          "error": "…",
          "code": "rate_limited",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_unavailable": {
        "summary": "unavailable",
        "value": {
          "error": "…",
          "code": "unavailable",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_key_verification_unavailable": {
        "summary": "key_verification_unavailable",
        "value": {
          "error": "…",
          "code": "key_verification_unavailable",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      },
      "error_method_not_allowed": {
        "summary": "method_not_allowed",
        "value": {
          "error": "…",
          "code": "method_not_allowed",
          "message": "…",
          "hint": "…",
          "docs": "https://www.analytiics.co/docs/api"
        }
      }
    }
  },
  "security": []
}