{"openapi":"3.1.0","info":{"title":"cheese tenant API","version":"0.2.0","description":"Event tracker + CDP on DuckDB. `/v1/*` is the public collector (browser SDK; `Authorization: Bearer <write_key>`, `?key=` or `body.writeKey`). Every `/api/*` endpoint is scoped to ONE tenant by its api_key (`Authorization: Bearer <api_key>`, or `?key=`). All timestamps are UTC; BIGINT values are serialised as strings. Ad-hoc SQL is read-only. Client IPs are never stored (only a salted hash). An MCP endpoint with the same capabilities is at POST /mcp (see docs/AGENTS.md)."},"servers":[{"url":"https://cheese.teamday.cc"}],"tags":[{"name":"collector","description":"public ingest endpoints hit by cheese.js (write key)"},{"name":"tenant","description":"tenant-scoped analytics + CDP API (api key)"}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"tenant API key, or an OAuth 2.1 access token obtained via /oauth/* (its read / write scope maps onto the same model; an OAuth token is never admin). Scopes: read (sk_r_…: GET, /api/sql, reports, funnel, retention, segment preview) ⊂ write (sk_w_…: + segments / attributes / campaigns dry runs / dashboards / webhooks / suppressions) ⊂ admin (sk_a_… and the legacy dashboard key: + real campaign sends, GDPR erasure, key management, audit log). 403 when the scope is too low; 429 + Retry-After when the per-key rate limit (API_RATE_PER_MIN, SQL_RATE_PER_MIN for /api/sql) is hit. Every non-GET call is audited."},"writeKey":{"type":"http","scheme":"bearer","description":"tenant write_key — public, embedded in the browser SDK; also accepted as `?key=` or `writeKey` in the JSON body"}},"schemas":{"ApiKey":{"type":"object","properties":{"tenant_id":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string","description":"first 8 characters of the key"},"scope":{"type":"string","enum":["read","write","admin"]},"created_at":{"type":"string"},"last_used_at":{"type":["string","null"]},"revoked_at":{"type":["string","null"]}}},"AuditRow":{"type":"object","properties":{"at":{"type":"string"},"principal":{"type":"string","description":"key id, key_legacy, scheduler, operator"},"scope":{"type":"string"},"surface":{"type":"string","enum":["rest","mcp","ui","system"]},"action":{"type":"string","description":"route (METHOD /api/…) or MCP tool name, erase_user, campaign.send"},"target":{"type":["string","null"]},"ok":{"type":"boolean"},"ms":{"type":["integer","null"]},"ip_hash":{"type":["string","null"]},"detail":{"description":"redacted, truncated input"}}},"Error":{"type":"object","properties":{"error":{"type":"string"},"issues":{"type":"array","items":{"type":"object"}}},"required":["error"]},"EventContext":{"type":"object","additionalProperties":true,"description":"Client context. `page` feeds events.url/path/referrer; `userAgent` overrides the request header for bot classification.","properties":{"page":{"type":"object","properties":{"url":{"type":"string"},"path":{"type":"string"},"referrer":{"type":"string"}}},"userAgent":{"type":"string"},"webdriver":{"type":"boolean"}}},"EventBody":{"type":"object","description":"One event without `type` (the endpoint sets it). timestamp is clamped to [now − 7 days, now]; messageId dedupes retries.","properties":{"event":{"type":"string","maxLength":200,"description":"track only: event name (e.g. signup_completed)"},"messageId":{"type":"string","maxLength":64,"description":"idempotency key (default: random UUID)"},"timestamp":{"oneOf":[{"type":"string","format":"date-time"},{"type":"number"}]},"anonymousId":{"type":"string","maxLength":128},"userId":{"type":"string","maxLength":128},"previousId":{"type":"string","maxLength":128,"description":"alias only: id to merge INTO userId"},"sessionId":{"type":"string","maxLength":64},"properties":{"type":"object","additionalProperties":true},"traits":{"type":"object","additionalProperties":true,"description":"identify only: profile traits (email, name, …)"},"context":{"$ref":"#/components/schemas/EventContext"},"writeKey":{"type":"string","description":"alternative to the Authorization header"}}},"IncomingEvent":{"allOf":[{"$ref":"#/components/schemas/EventBody"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["track","page","identify","alias"]}}}]},"IncomingBatch":{"type":"object","required":["batch"],"properties":{"batch":{"type":"array","minItems":1,"maxItems":500,"items":{"$ref":"#/components/schemas/IncomingEvent"}},"sentAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"number"}],"description":"client send time; used to correct clock skew of the event timestamps"},"writeKey":{"type":"string"}}},"CollectResult":{"type":"object","required":["ok","n"],"properties":{"ok":{"type":"boolean"},"n":{"type":"integer","description":"events accepted"}}},"AttributeDef":{"type":"object","required":["name","type"],"description":"A per-user aggregate compiled into one GROUP BY user_id pass over events (or sessions).","properties":{"name":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,62}$"},"type":{"type":"string","enum":["count","count_distinct","sum","min","max","avg","first","last","exists"]},"event":{"type":"string","default":"*","description":"event name, \"*\" for any event, \"$session\" for derived sessions"},"field":{"type":"string","description":"ts|path|url|referrer|country|ua|name|session_id or props.<key>; for $session: started_at|ended_at|events|landing_path|referrer"},"window":{"type":"string","pattern":"^\\d+[hdw]$","description":"e.g. 7d, 24h, 2w — relative to now()"},"where":{"type":"array","items":{"type":"object","required":["field","op","value"],"properties":{"field":{"type":"string"},"op":{"type":"string","enum":["=","!=","contains"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}}}}}},"SegmentValue":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]},"description":"for in / not_in (list) and between ([low, high])"}]},"AttrRule":{"type":"object","required":["attr","op"],"description":"compare a user_vectors column with a constant","properties":{"kind":{"type":"string","enum":["attr"]},"attr":{"type":"string","pattern":"^[a-z_][a-z0-9_]{0,62}$","description":"a user_vectors column"},"op":{"type":"string","enum":["=","!=",">",">=","<","<=","contains","starts_with","in","not_in","between","is_set","not_set","after","before","within_days","not_within_days"],"description":"within_days / not_within_days: timestamp column ≥ / < now − value days"},"value":{"$ref":"#/components/schemas/SegmentValue"}}},"EventWhere":{"type":"object","required":["field","op"],"properties":{"field":{"type":"string","description":"ts|path|url|referrer|country|ua|name|session_id or props.<key>"},"op":{"type":"string","enum":["=","!=",">",">=","<","<=","contains","starts_with","in","not_in","between","is_set","not_set"]},"value":{"$ref":"#/components/schemas/SegmentValue"}}},"EventRule":{"type":"object","required":["kind","name","op"],"description":"the person has (not) sent an event; compiled to a bound subquery over events (bots excluded)","properties":{"kind":{"type":"string","enum":["event"]},"name":{"type":"string","description":"event name; \"*\" = any client event; system events ($email_sent) only when named"},"op":{"type":"string","enum":["did","did_not"]},"count":{"type":"object","required":["op","value"],"properties":{"op":{"type":"string","enum":["=","!=",">",">=","<","<="]},"value":{"type":"integer","minimum":0}},"description":"number of matching events (default ≥ 1)"},"within_days":{"type":"integer","minimum":0,"maximum":3650,"description":"only events of the last N days"},"where":{"type":"array","maxItems":20,"items":{"$ref":"#/components/schemas/EventWhere"}}}},"SequenceRule":{"type":"object","required":["kind","steps"],"description":"did A then B (…): first occurrence of every step in order (funnel semantics)","properties":{"kind":{"type":"string","enum":["sequence"]},"steps":{"type":"array","minItems":2,"maxItems":8,"items":{"type":"string"}},"within_days":{"type":"integer","minimum":0,"maximum":3650,"description":"first(last step) − first(first step) ≤ N days"},"since_days":{"type":"integer","minimum":0,"maximum":3650,"description":"only look at events of the last N days"}}},"SegmentRule":{"oneOf":[{"$ref":"#/components/schemas/AttrRule"},{"$ref":"#/components/schemas/EventRule"},{"$ref":"#/components/schemas/SequenceRule"}]},"RuleGroup":{"type":"object","required":["rules"],"description":"one level of nesting: (a AND b) OR c","properties":{"match":{"type":"string","enum":["all","any"],"default":"all"},"rules":{"type":"array","minItems":1,"maxItems":50,"items":{"$ref":"#/components/schemas/SegmentRule"}}}},"SegmentDef":{"type":"object","required":["rules"],"properties":{"match":{"type":"string","enum":["all","any"],"default":"all"},"rules":{"type":"array","minItems":1,"maxItems":50,"items":{"oneOf":[{"$ref":"#/components/schemas/SegmentRule"},{"$ref":"#/components/schemas/RuleGroup"}]}}}},"Segment":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"def":{"$ref":"#/components/schemas/SegmentDef"},"created_at":{"type":"string"},"size":{"type":"integer"},"preset":{"type":"boolean"}}},"SegmentUpdate":{"type":"object","description":"Partial update; omitted fields keep their value. rebuild=true (default) re-materialises membership now.","properties":{"name":{"type":"string"},"def":{"$ref":"#/components/schemas/SegmentDef"},"rebuild":{"type":"boolean","default":true}}},"UserVector":{"type":"object","description":"One row of user_vectors: base columns + every declared attribute","additionalProperties":true,"properties":{"user_id":{"type":"string"},"email":{"type":["string","null"]},"name":{"type":["string","null"]},"first_seen":{"type":"string"},"last_seen":{"type":"string"},"events_total":{"type":"string","description":"BIGINT as string"},"sessions_total":{"type":"string"}}},"Erasure":{"type":"object","description":"Result of a GDPR erasure","required":["deleted_user","ids","events","raw"],"properties":{"deleted_user":{"type":"string","description":"canonical id of the erased person"},"ids":{"type":"array","items":{"type":"string"},"description":"every external id that was erased and tombstoned"},"events":{"type":"integer"},"rows":{"type":"object","additionalProperties":{"type":"integer"},"description":"rows deleted per table"},"raw":{"type":"object","properties":{"status":{"type":"string","enum":["purged","queued","none"],"description":"raw JSONL rewritten inline | in the background | no raw log"},"files":{"type":"integer"},"removed":{"type":"integer"}}},"already_erased":{"type":"boolean"}}},"CampaignInput":{"type":"object","required":["name","segment_id","subject","body"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"segment_id":{"type":"string"},"subject":{"type":"string","description":"template; {{name}} etc. = user_vectors columns (CR/LF stripped)"},"body":{"type":"string","description":"HTML template: your markup stays raw, substituted {{values}} are HTML-escaped; {{unsubscribe_url}} = signed one-click unsubscribe link"},"cap_days":{"type":"integer","minimum":1,"default":7,"description":"do not email the same person by this campaign again within N days (minimum 1)"},"active":{"type":"boolean","default":false,"description":"true = queued for sending automatically after every rebuild (rate limited, EMAIL_RATE_PER_SEC)"}}},"Campaign":{"allOf":[{"$ref":"#/components/schemas/CampaignInput"},{"type":"object","properties":{"tenant_id":{"type":"string"},"sent":{"type":"integer"},"failed":{"type":"integer"}}}]},"CampaignRun":{"type":"object","properties":{"campaign":{"type":"string"},"eligible":{"type":"integer"},"sent":{"type":"integer"},"failed":{"type":"integer"},"suppressed":{"type":"integer","description":"addresses added to the suppression list during this run (3 failed deliveries)"},"dryRun":{"type":"boolean"},"sample":{"type":"array","items":{"type":"string"}}}},"WebhookInput":{"type":"object","required":["name","segment_id","url"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"segment_id":{"type":"string"},"on":{"type":"string","enum":["enter","exit","both"],"default":"enter","description":"which membership transitions fire it"},"kind":{"type":"string","enum":["http","slack"],"default":"http","description":"http = signed JSON payload; slack = {text} rendered from template to a Slack incoming-webhook URL"},"url":{"type":"string","description":"public http(s) target (loopback / private networks rejected unless WEBHOOK_ALLOW_PRIVATE)"},"secret":{"type":"string","minLength":8,"description":"HMAC-SHA256 key for X-Cheese-Signature; generated when omitted"},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"extra request headers (max 20)"},"template":{"type":"string","description":"slack only: {{name}} {{action}} {{segment}} {{email}} + any user_vectors column"},"active":{"type":"boolean","default":false,"description":"true = fires after every rebuild"}}},"Webhook":{"allOf":[{"$ref":"#/components/schemas/WebhookInput"},{"type":"object","properties":{"tenant_id":{"type":"string"},"created_at":{"type":"string"},"sent":{"type":"integer"},"failed":{"type":"integer"}}}]},"WebhookPayload":{"type":"object","description":"What kind=http webhooks receive. Headers: X-Cheese-Signature: sha256=<hex HMAC-SHA256 of the raw body with the secret>, X-Cheese-Event, X-Cheese-Delivery (idempotency key), X-Cheese-Webhook.","properties":{"event":{"type":"string","enum":["segment.entered","segment.exited"]},"tenant":{"type":"string"},"segment":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}},"user":{"$ref":"#/components/schemas/UserVector"},"at":{"type":"string","description":"snapshot time (entered_at / exited_at), ISO 8601 UTC"},"webhook":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}},"test":{"type":"boolean","description":"present on POST /api/webhooks/{id}/test payloads"}}},"WebhookDelivery":{"type":"object","properties":{"webhook_id":{"type":"string"},"user_id":{"type":"string"},"event":{"type":"string"},"attempt":{"type":"integer"},"status":{"type":"string","enum":["sent","retry","failed"]},"http_status":{"type":["integer","null"]},"error":{"type":["string","null"]},"sent_at":{"type":"string"}}},"WebhookTest":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":["integer","null"]},"ms":{"type":"number"},"error":{"type":"string"},"event":{"type":"string"}}},"Suppression":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"reason":{"type":"string","default":"manual","description":"unsubscribed | failed Nx: … | manual"},"created_at":{"type":"string"}}},"Report":{"type":"object","description":"Every report carries rows, the exact sql (bind values inlined), ms and period; extra keys per report.","additionalProperties":true,"properties":{"rows":{"type":"array","items":{"type":"object"}},"sql":{"type":"string"},"ms":{"type":"number"},"period":{"type":"object"},"queries":{"type":"array","items":{"type":"object"}}}},"Funnel":{"type":"object","properties":{"period":{"type":"object"},"window":{"type":["string","null"]},"window_seconds":{"type":["integer","null"]},"steps":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"users":{"type":"integer"},"rate":{"type":["number","null"],"description":"% of previous step"},"overall":{"type":"number","description":"% of first step"},"dropped":{"type":["integer","null"],"description":"users who reached this step but not the next"},"median_seconds":{"type":["integer","null"],"description":"median time to the next step over the users who reached it"}}}},"breakdown":{"type":"object","description":"only with the breakdown parameter","properties":{"by":{"type":"string"},"groups":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"users":{"type":"array","items":{"type":"integer"},"description":"per step"}}}}}}}},"SqlResult":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object"}},"columns":{"type":"array","items":{"type":"string"}},"ms":{"type":"number"}}},"WidgetSource":{"oneOf":[{"type":"object","required":["kind","name"],"properties":{"kind":{"const":"report"},"name":{"type":"string","enum":["overview","trends","retention","cohorts","sources","transitions","pages","page","segment-sizes","segment-entries","segment-compare","events","event-props","ai-visibility"]},"params":{"type":"object","additionalProperties":true,"description":"dim, touch, event, segment, weeks, limit, metric (series column); ai-visibility: section (bots|categories|crawled_pages|referrals|referral_landings|citations) for tables, category for a per-day crawl series"}}},{"type":"object","required":["kind","sql"],"properties":{"kind":{"const":"sql"},"sql":{"type":"string","description":"DuckDB SELECT. Placeholders {{period_start}} / {{period_end}} / {{prev_start}} / {{prev_end}} (TIMESTAMP literals of the selected period and the one before) and {{days}}. metric: first cell = value, delta from a 2nd column named prev or (when the SQL uses the period placeholders) from the same query over the previous period; series: a day/date column + one numeric column per line."}}},{"type":"object","required":["kind","steps"],"properties":{"kind":{"const":"funnel"},"steps":{"type":"array","items":{"type":"string"},"minItems":2},"window":{"type":"string"}}},{"type":"object","required":["kind","id","section"],"properties":{"kind":{"const":"journey"},"id":{"type":"string"},"version":{"type":"integer","minimum":1},"section":{"enum":["funnel","retention","cohorts"]}}},{"type":"object","required":["kind"],"properties":{"kind":{"const":"retention"},"params":{"type":"object","additionalProperties":true}}},{"type":"object","required":["kind","key"],"properties":{"kind":{"const":"metric"},"key":{"type":"string"}}},{"type":"object","required":["kind","md"],"properties":{"kind":{"const":"text"},"md":{"type":"string"}}}]},"Widget":{"type":"object","required":["type","title","source"],"properties":{"id":{"type":"string"},"type":{"type":"string","enum":["metric","series","table","funnel","retention","text"]},"title":{"type":"string"},"w":{"type":"integer","enum":[1,2,3],"description":"width in a 3-column grid"},"source":{"$ref":"#/components/schemas/WidgetSource"}}},"DashboardInput":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"widgets":{"type":"array","items":{"$ref":"#/components/schemas/Widget"}}}},"Dashboard":{"allOf":[{"$ref":"#/components/schemas/DashboardInput"},{"type":"object","required":["id","updated_at"],"properties":{"id":{"type":"string"},"updated_at":{"type":"string"}}}]}}},"paths":{"/api/site-tag":{"get":{"operationId":"getSiteTag","summary":"Read live tag rules, web personalization and current revision","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"publishSiteTag","summary":"Publish complete website configuration; expectedRevision prevents concurrent overwrites","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"invalid configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"write scope required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"revision conflict; read latest config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"expectedRevision":{"type":"integer","minimum":0,"maximum":9007199254740991},"config":{"type":"object","properties":{"enabled":{"default":true,"type":"boolean"},"rules":{"maxItems":100,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,80}$"},"name":{"type":"string","minLength":1,"maxLength":200},"enabled":{"default":false,"type":"boolean"},"hosts":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"string","pattern":"^(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)*[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$"}},"pathPrefix":{"default":"/","type":"string","maxLength":1000,"pattern":"^\\/.*"},"trigger":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"page"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"click"},"selector":{"type":"string","minLength":1,"maxLength":500}},"required":["kind","selector"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"scroll"},"percent":{"type":"number","minimum":1,"maximum":100}},"required":["kind","percent"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"delay"},"seconds":{"type":"number","minimum":1,"maximum":3600}},"required":["kind","seconds"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"event"},"name":{"type":"string","minLength":1,"maxLength":200},"property":{"type":"string","minLength":1,"maxLength":200},"equals":{"anyOf":[{"type":"string","maxLength":500},{"type":"number"},{"type":"boolean"}]}},"required":["kind","name"],"additionalProperties":false}]},"event":{"type":"string","minLength":1,"maxLength":200},"oncePerPage":{"default":true,"type":"boolean"},"properties":{"default":{},"type":"object","propertyNames":{"type":"string","maxLength":80},"additionalProperties":{"anyOf":[{"type":"string","maxLength":500},{"type":"number"},{"type":"boolean"}]}},"attributes":{"default":{},"type":"object","propertyNames":{"type":"string","maxLength":80},"additionalProperties":{"type":"string","pattern":"^data-[a-z0-9_-]{1,80}$"}}},"required":["id","name","enabled","hosts","pathPrefix","trigger","event","oncePerPage","properties","attributes"],"additionalProperties":false}},"layers":{"maxItems":30,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,80}$"},"name":{"type":"string","minLength":1,"maxLength":200},"enabled":{"default":false,"type":"boolean"},"hosts":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"string","pattern":"^(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)*[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$"}},"pathPrefix":{"default":"/","type":"string","maxLength":1000,"pattern":"^\\/.*"},"trigger":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"page"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"click"},"selector":{"type":"string","minLength":1,"maxLength":500}},"required":["kind","selector"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"scroll"},"percent":{"type":"number","minimum":1,"maximum":100}},"required":["kind","percent"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"delay"},"seconds":{"type":"number","minimum":1,"maximum":3600}},"required":["kind","seconds"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"event"},"name":{"type":"string","minLength":1,"maxLength":200},"property":{"type":"string","minLength":1,"maxLength":200},"equals":{"anyOf":[{"type":"string","maxLength":500},{"type":"number"},{"type":"boolean"}]}},"required":["kind","name"],"additionalProperties":false}]},"title":{"type":"string","minLength":1,"maxLength":200},"body":{"default":"","type":"string","maxLength":2000},"image":{"type":"string","maxLength":2048,"format":"uri"},"ctaLabel":{"type":"string","minLength":1,"maxLength":200},"ctaUrl":{"type":"string","maxLength":2048,"format":"uri"},"html":{"default":"","type":"string","maxLength":20000},"js":{"default":"","type":"string","maxLength":10000},"capHours":{"default":24,"type":"number","minimum":1,"maximum":8760}},"required":["id","name","enabled","hosts","pathPrefix","trigger","title","body","ctaLabel","ctaUrl","html","js","capHours"],"additionalProperties":false}}},"required":["enabled","rules","layers"],"additionalProperties":false}},"required":["expectedRevision","config"],"additionalProperties":false}}}}}},"/api/site-tag/activity":{"get":{"operationId":"siteTagActivity","summary":"Observed rule and web personalization event counts and last seen, excluding bots, over 30 days","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/site-tag/history":{"get":{"operationId":"siteTagHistory","summary":"Latest 50 complete revisions, editor and timestamp; restore by publishing an old config with the current revision","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tag/config":{"get":{"operationId":"publicSiteTag","summary":"Browser configuration, enabled entries filtered by exact Origin hostname; served by API owner","security":[],"parameters":[{"name":"key","in":"query","required":true,"schema":{"type":"string"},"description":"Public website write key"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"401":{"description":"invalid write key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/page-intelligence":{"get":{"operationId":"pageIntelligence","summary":"Saved page history, search metrics, and AI citation evidence","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string"},"description":"Exact page path"},{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":90,"default":28},"description":"Requested comparison period"}]}},"/api/page-intelligence/diff":{"get":{"operationId":"pageFileDiff","summary":"Compare UTF-8 file contents at two recorded page commits (512 KiB per file)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string"},"description":"path"},{"name":"file","in":"query","required":true,"schema":{"type":"string"},"description":"file"},{"name":"base","in":"query","required":true,"schema":{"type":"string"},"description":"base"},{"name":"head","in":"query","required":true,"schema":{"type":"string"},"description":"head"}]}},"/api/page-intelligence/versions":{"post":{"operationId":"importPageVersions","summary":"Import mapped source/deployment evidence (write scope). Versions require path, id, sha, title, committed_at and sources.","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["versions"],"properties":{"versions":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"object","additionalProperties":true}}}}}}}}},"/api/outcomes":{"post":{"operationId":"recordApplicationOutcome","summary":"Record a completed application event using a private write/admin API key (202 queued)","security":[{"bearer":[]}],"responses":{"202":{"description":"Queued; verify ingestion in tracking health","content":{"application/json":{"schema":{}}}},"401":{"description":"Invalid private key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Tracking plan validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["event_id","user_id","event"],"properties":{"event_id":{"type":"string","maxLength":200},"user_id":{"type":"string","maxLength":200},"event":{"type":"string","maxLength":200},"timestamp":{"type":"string","format":"date-time"},"schema_version":{"type":"integer","minimum":1},"properties":{"type":"object"}}}}}}}},"/api/site-insights":{"get":{"operationId":"siteInsights","summary":"Site analyses with measurement coverage","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"in":"query","name":"site","schema":{"type":"string"}},{"in":"query","name":"analysis","schema":{"type":"string","enum":["changes","opportunities","queries","groups","journeys","audiences","impact","overlap","monitor","outcomes","measurement"]}},{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}},{"in":"query","name":"goal","schema":{"type":"string"}},{"in":"query","name":"group","schema":{"enum":["type","locale","topic"]}},{"in":"query","name":"horizon","schema":{"type":"integer","minimum":1,"maximum":30,"default":7}},{"in":"query","name":"query","schema":{"type":"string"}}]}},"/api/site-insights/settings":{"put":{"operationId":"saveSiteInsightSettings","summary":"Save site classification and outcome mappings (admin)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["site","settings"],"properties":{"site":{"type":"string"},"settings":{"type":"object"}}}}}}}},"/api/site-insights/refresh":{"post":{"operationId":"refreshSiteSearchDetails","summary":"Import daily query, device, country and search appearance data (admin)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["site"],"properties":{"site":{"type":"string"},"days":{"type":"integer","minimum":1,"maximum":90,"default":30},"kinds":{"type":"array","items":{"enum":["query","device","country","searchAppearance"]}}}}}}}}},"/api/site-performance":{"get":{"operationId":"sitePerformance","summary":"Site-scoped search, landing sessions and selected goal reporting","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"in":"query","name":"site","schema":{"type":"string"}},{"in":"query","name":"end","description":"Inclusive reporting end date (Pacific), at least three days before today. Comparison is the preceding equal-length period.","schema":{"type":"string","format":"date"}},{"in":"query","name":"goal","schema":{"type":"string","default":"signup_completed"}},{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}}]}},"/api/site-performance/refresh":{"post":{"operationId":"refreshSitePerformance","summary":"Import site-wide daily Search Console data (admin scope)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["site"],"properties":{"site":{"type":"string"},"end":{"type":"string","format":"date"},"days":{"type":"integer","minimum":1,"maximum":90,"default":30}}}}}}}},"/api/page-intelligence/refresh":{"post":{"operationId":"refreshPageEvidence","summary":"Refresh GitHub or Search Console evidence (admin scope)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["path","provider"],"properties":{"path":{"type":"string"},"provider":{"enum":["github","google"]},"days":{"type":"integer","minimum":1,"maximum":90,"default":28}}}}}}}},"/api/models":{"get":{"operationId":"listModels","summary":"Predictive models: task catalog (targets, sites, data range, defaults) and the trained CHAID trees of this workspace","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/models/train":{"post":{"operationId":"trainModel","summary":"Train a CHAID decision tree on a leak-free point-in-time dataset (write scope). task = signup_intent (predict the target event at the first pageview) or retention (new session within horizon_days after daily cutoffs).","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["task"],"properties":{"task":{"enum":["signup_intent","retention"]},"name":{"type":"string"},"target":{"type":"string"},"site":{"type":"string"},"horizon_hours":{"type":"integer","minimum":1,"maximum":336,"default":24},"horizon_days":{"type":"integer","minimum":1,"maximum":30,"default":3},"max_cutoffs":{"type":"integer","minimum":3,"maximum":60,"default":14},"holdout_share":{"type":"number","minimum":0.1,"maximum":0.5,"default":0.3},"max_depth":{"type":"integer","minimum":1,"maximum":8,"default":5},"alpha_split":{"type":"number","default":0.05},"alpha_merge":{"type":"number","default":0.05},"min_parent":{"type":"integer","default":50},"min_child":{"type":"integer","default":20}}}}}}}},"/api/growth":{"get":{"operationId":"growth","summary":"Growth studio: creative kinds, OpenAI connection state, today's image usage, the brand brief and every generated creative with signed image URLs","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/growth/brand":{"put":{"operationId":"saveBrand","summary":"Save the brand brief the generation prompts use (write scope)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["brand"],"properties":{"brand":{"type":"string","maxLength":8000}}}}}}}},"/api/growth/creatives":{"post":{"operationId":"generateCreative","summary":"Generate a creative with the workspace's OpenAI connection (write scope; returns 202 with status running — poll the creative until ready or failed). kind = google_ads | onsite_banner | video_storyboard | email | cold_email | search_snippet; source = the evidence row to ground it in; brief = extra instructions.","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["kind"],"properties":{"kind":{"enum":["google_ads","onsite_banner","video_storyboard","email","cold_email","search_snippet"]},"playbook":{"type":"string"},"name":{"type":"string"},"brief":{"type":"string","maxLength":3000},"source":{"type":"object","properties":{"url":{"type":"string"},"kind":{"type":"string"},"evidence":{"type":"string"},"action":{"type":"string"},"goal":{"type":"string"},"site":{"type":"string"},"period":{"type":"string"},"title":{"type":"string"}}}}}}}}}},"/api/growth/creatives/{id}":{"get":{"operationId":"getCreative","summary":"One creative: status, progress, spec, usage, image URLs","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"creative id"}]},"put":{"operationId":"updateCreative","summary":"Rename, change the review stage (draft | approved | launched | archived) or edit the spec of a ready creative (write scope)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"creative id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"stage":{"enum":["draft","approved","launched","archived"]},"name":{"type":"string"},"spec":{"type":"object"}}}}}}},"delete":{"operationId":"deleteCreative","summary":"Delete a creative and its images","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"creative id"}]}},"/api/growth/guidelines":{"put":{"operationId":"saveGrowthGuidelines","summary":"Replace the growth guidelines: voice, audience, facts, visual, decisions (write scope)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"voice":{"type":"string"},"audience":{"type":"string"},"facts":{"type":"string"},"visual":{"type":"string"},"decisions":{"type":"array","items":{"type":"object","required":["at","text"],"properties":{"at":{"type":"string"},"text":{"type":"string"},"source":{"type":"string"}}}}}}}}}}},"/api/growth/guidelines/decisions":{"post":{"operationId":"addGrowthDecision","summary":"Append one dated decision the studio must follow from now on (write scope)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text"],"properties":{"text":{"type":"string","maxLength":1000},"source":{"type":"string"}}}}}}}},"/api/growth/creatives/{id}/adjust":{"post":{"operationId":"adjustCreative","summary":"Create a revision with reviewer notes (write scope; 202, poll the new creative). scope=all rewrites copy and images, scope=images keeps the copy; remember=true stores the notes as a decision.","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"creative id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["instructions"],"properties":{"instructions":{"type":"string","maxLength":2000},"remember":{"type":"boolean","default":false},"scope":{"enum":["all","images"],"default":"all"}}}}}}}},"/api/growth/creatives/{id}/assets/{asset}/redo":{"post":{"operationId":"redoCreativeAsset","summary":"Re-render one image of a ready creative in place with optional notes (write scope; 202, poll the creative)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"creative id"},{"name":"asset","in":"path","required":true,"schema":{"type":"string"},"description":"asset id"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"instructions":{"type":"string","maxLength":2000}}}}}}}},"/api/growth/creatives/{id}/email-campaign":{"post":{"operationId":"creativeToEmailCampaign","summary":"Turn one email of a ready email creative into an inactive email campaign for a segment (write scope). Sending stays a separate call.","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"creative id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["segment_id"],"properties":{"segment_id":{"type":"string"},"email":{"type":"integer","minimum":0,"maximum":2,"default":0},"subject":{"type":"integer","minimum":0,"maximum":2,"default":0},"name":{"type":"string"},"cap_days":{"type":"integer","minimum":1,"default":7}}}}}}}},"/api/models/{id}":{"get":{"operationId":"getModel","summary":"One trained model with its summary metrics and full tree (nodes carry training and holdout counts)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"model id"}]},"delete":{"operationId":"deleteModel","summary":"Delete a trained model","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"model id"}]}},"/api/page-intelligence/citations":{"post":{"operationId":"checkPageCitation","summary":"Run a bounded paid web-search citation sample (admin scope)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["path","prompt"],"properties":{"path":{"type":"string"},"prompt":{"type":"string","minLength":10,"maxLength":1000}}}}}}}},"/v1/batch":{"post":{"operationId":"collectBatch","summary":"Ingest a batch of events (what cheese.js sends)","description":"Up to 500 events per call, body ≤ 2 MB; `text/plain` bodies (sendBeacon) are parsed as JSON. Events are validated, stamped with server time / country (IP is hashed, never stored), appended to the raw JSONL log and queued; the response does not wait for the write.","tags":["collector"],"security":[{"writeKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncomingBatch"}}}},"responses":{"200":{"description":"accepted (queued; raw JSONL log appended)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectResult"}}}},"400":{"description":"invalid payload — `issues` lists the first zod problems","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid write key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"body over 2 MB","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/track":{"post":{"operationId":"collectTrack","summary":"Ingest one custom event","description":"Same as one `{type:\"track\"}` element of /v1/batch. `event` is the event name; `anonymousId` and/or `userId` identify the person.","tags":["collector"],"security":[{"writeKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventBody"}}}},"responses":{"200":{"description":"accepted (queued; raw JSONL log appended)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectResult"}}}},"400":{"description":"invalid payload — `issues` lists the first zod problems","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid write key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"body over 2 MB","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/page":{"post":{"operationId":"collectPage","summary":"Ingest one page view","description":"Same as one `{type:\"page\"}` element of /v1/batch (stored as event `$page`); put url/path/referrer in `context.page` or `properties`.","tags":["collector"],"security":[{"writeKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventBody"}}}},"responses":{"200":{"description":"accepted (queued; raw JSONL log appended)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectResult"}}}},"400":{"description":"invalid payload — `issues` lists the first zod problems","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid write key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"body over 2 MB","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/identify":{"post":{"operationId":"collectIdentify","summary":"Attach a userId (and traits) to an anonymous visitor","description":"Same as one `{type:\"identify\"}` element of /v1/batch. `anonymousId` → `userId` is claimed only if the anon id never belonged to another user; `traits` merge into the profile.","tags":["collector"],"security":[{"writeKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventBody"}}}},"responses":{"200":{"description":"accepted (queued; raw JSONL log appended)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectResult"}}}},"400":{"description":"invalid payload — `issues` lists the first zod problems","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid write key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"body over 2 MB","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/alias":{"post":{"operationId":"collectAlias","summary":"Merge two ids explicitly","description":"Same as one `{type:\"alias\"}` element of /v1/batch: everything that resolved to `previousId` now resolves to `userId` (transitive).","tags":["collector"],"security":[{"writeKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventBody"}}}},"responses":{"200":{"description":"accepted (queued; raw JSONL log appended)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectResult"}}}},"400":{"description":"invalid payload — `issues` lists the first zod problems","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid write key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"body over 2 MB","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/cheese.js":{"get":{"operationId":"sdkScript","summary":"The browser SDK (4.5 KB): init / track / page / identify / merge / reset","tags":["collector"],"responses":{"200":{"description":"JavaScript","content":{"application/javascript":{"schema":{"type":"string"}}}}}}},"/health":{"get":{"operationId":"health","summary":"Liveness: redis, queue, control DB, scheduler tick","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"checks":{"type":"object","additionalProperties":true}}}}}},"503":{"description":"one or more checks failed","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/api/me":{"get":{"operationId":"getMe","summary":"Tenant info (id, name, write_key, vertical, SDK url)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"setVertical","summary":"Set the tenant vertical","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["vertical"],"properties":{"vertical":{"type":"string","enum":["saas","ecommerce","content"]}}}}}}}},"/api/metrics/overview":{"get":{"operationId":"metricsOverview","summary":"AARRR panel, new vs returning, daily trend, top events for the period","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":730,"default":30},"description":"Period = the last N whole UTC days including today."}]}},"/api/measurement/health":{"get":{"operationId":"measurementHealth","summary":"Observed taxonomy event coverage and freshness; unobserved is not verified zero outcomes","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":730,"default":30},"description":"Period = the last N whole UTC days including today."}]}},"/api/companies":{"get":{"operationId":"listCompanies","summary":"Account engagement with confirmed, associated and unassigned activity","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":730,"default":30},"description":"Period = the last N whole UTC days including today."},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":200},"description":"Account name, domain or ID"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":100},"description":"Maximum accounts"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0},"description":"Pagination offset"}]},"post":{"operationId":"upsertCompany","summary":"Create or update a sourced account (write scope)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","minLength":1,"maxLength":200},"name":{"type":"string","minLength":1,"maxLength":300},"domain":{"type":["string","null"],"description":"Hostname only; optional. An application account does not establish a legal-company relationship."},"traits":{"type":"object","additionalProperties":true}}}}}}}},"/api/companies/{id}":{"get":{"operationId":"getCompany","summary":"Account profile, people, membership evidence and recent attributed activity","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account ID"},{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":730,"default":30},"description":"Period = the last N whole UTC days including today."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":100},"description":"Maximum rows per detail list"}]},"delete":{"operationId":"deleteCompany","summary":"Delete the account and all its memberships; events keep their company context (write scope)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"},"id":{"type":"string"},"memberships_removed":{"type":"integer"}}}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"unknown account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account ID"}]}},"/api/companies/{id}/members/{personId}":{"put":{"operationId":"setCompanyMember","summary":"Record known person membership with source and evidence (write scope)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account ID"},{"name":"personId","in":"path","required":true,"schema":{"type":"string"},"description":"Known external person ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status","source"],"properties":{"status":{"type":"string","enum":["confirmed","inferred"]},"source":{"type":"string","minLength":1,"maxLength":100},"evidence":{"type":"string","maxLength":2000}}}}}}},"delete":{"operationId":"removeCompanyMember","summary":"Remove the person’s current account relationship (write scope)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account ID"},{"name":"personId","in":"path","required":true,"schema":{"type":"string"},"description":"Known external person ID"}]}},"/api/company-candidates":{"get":{"operationId":"companyCandidates","summary":"Unverified business-email domains and browser-reported organizations from profiles","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":200},"description":"Filter candidates"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":100},"description":"Maximum candidates"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0},"description":"Pagination offset"}]}},"/api/analytics/definitions":{"get":{"operationId":"listJourneys","summary":"List current shared journey definitions and their versions","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/analytics/definitions/{id}":{"get":{"operationId":"getJourney","summary":"Read a shared journey definition, optionally at an immutable version","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Journey ID"},{"name":"version","in":"query","required":false,"schema":{"type":"integer","minimum":1},"description":"Definition version; latest if omitted"}]},"put":{"operationId":"saveJourney","summary":"Save a new immutable journey definition version (write scope)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Journey ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"default":"","type":"string","maxLength":2000},"steps":{"minItems":2,"maxItems":8,"type":"array","items":{"type":"object","properties":{"event":{"type":"string","minLength":1,"maxLength":200},"label":{"type":"string","minLength":1,"maxLength":200},"where":{"default":[],"maxItems":10,"type":"array","items":{"type":"object","properties":{"field":{"type":"string","pattern":"^(path|url|referrer|country|props\\.[A-Za-z0-9_.-]{1,64})$"},"op":{"type":"string","enum":["=","!=","contains",">",">=","<","<="]},"value":{"anyOf":[{"type":"string","maxLength":1000},{"type":"number"},{"type":"boolean"}]}},"required":["field","op","value"],"additionalProperties":false}},"occurrences":{"default":1,"type":"integer","minimum":1,"maximum":100},"source":{"default":"all","type":"string","enum":["all","authenticated"]}},"required":["event","where","occurrences","source"],"additionalProperties":false}},"activation_step":{"default":1,"type":"integer","minimum":1,"maximum":7},"return_event":{"type":"object","properties":{"event":{"type":"string","minLength":1,"maxLength":200},"label":{"type":"string","minLength":1,"maxLength":200},"where":{"default":[],"maxItems":10,"type":"array","items":{"type":"object","properties":{"field":{"type":"string","pattern":"^(path|url|referrer|country|props\\.[A-Za-z0-9_.-]{1,64})$"},"op":{"type":"string","enum":["=","!=","contains",">",">=","<","<="]},"value":{"anyOf":[{"type":"string","maxLength":1000},{"type":"number"},{"type":"boolean"}]}},"required":["field","op","value"],"additionalProperties":false}},"occurrences":{"default":1,"type":"integer","minimum":1,"maximum":100},"source":{"default":"all","type":"string","enum":["all","authenticated"]}},"required":["event","where","occurrences","source"],"additionalProperties":false},"horizon_days":{"default":30,"type":"integer","minimum":1,"maximum":90},"retention_days":{"default":[1,7,30],"minItems":1,"maxItems":8,"type":"array","items":{"type":"integer","minimum":1,"maximum":90}}},"required":["name","description","steps","activation_step","return_event","horizon_days","retention_days"],"additionalProperties":false}}}}}},"/api/analytics/journeys/{id}":{"get":{"operationId":"journeyReport","summary":"Ordered acquisition outcomes, mature conversion, meaningful retention and acquisition groups","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Journey ID"},{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":365,"default":30},"description":"Acquisition period, including today; follow-up ends now"},{"name":"version","in":"query","required":false,"schema":{"type":"integer","minimum":1},"description":"Definition version"},{"name":"group","in":"query","required":false,"schema":{"enum":["channel","landing","week"]},"description":"Acquisition grouping"}]}},"/api/analytics/journeys/{id}/people":{"get":{"operationId":"journeyPeople","summary":"Paginated people reaching a stage, mature drop-offs or pending follow-up","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Journey ID"},{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":365,"default":30},"description":"Acquisition period"},{"name":"version","in":"query","required":false,"schema":{"type":"integer","minimum":1},"description":"Definition version"},{"name":"step","in":"query","required":true,"schema":{"type":"integer","minimum":0,"maximum":7},"description":"Zero-based stage"},{"name":"status","in":"query","required":false,"schema":{"enum":["reached","dropped","pending"]},"description":"Membership condition"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0},"description":"Pagination offset"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100},"description":"Page size"}]}},"/api/measurement/plan":{"get":{"operationId":"trackingPlan","summary":"List current event contracts, owners and required properties","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/measurement/plan/{event}":{"put":{"operationId":"saveTrackingPlan","summary":"Save an event contract revision; private outcome requests must satisfy it (write scope)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"event","in":"path","required":true,"schema":{"type":"string"},"description":"Exact event name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"description":{"default":"","type":"string","maxLength":2000},"owner":{"type":"string","minLength":1,"maxLength":200},"required":{"default":[],"maxItems":30,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9_]{0,63}$"},"type":{"type":"string","enum":["string","number","boolean"]}},"required":["name","type"],"additionalProperties":false}}},"required":["description","owner","required"],"additionalProperties":false}}}}}},"/api/measurement/tracking":{"get":{"operationId":"trackingHealth","summary":"Observed and authenticated events, current-contract property failures and delivery latency","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":365,"default":30},"description":"Observation period"}]}},"/api/replays":{"get":{"operationId":"listReplays","summary":"List up to 100 recent recordings","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"user","in":"query","required":false,"schema":{"type":"string","maxLength":200},"description":"Any external person ID"}]}},"/api/replays/{id}":{"get":{"operationId":"getReplay","summary":"Read a masked recording and its completeness information","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"recording not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Recording ID"}]},"delete":{"operationId":"deleteReplay","summary":"Delete recording payloads and reject queued retries (admin scope)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Recording ID"}]}},"/v1/replays":{"post":{"operationId":"collectReplay","summary":"Queue an ordered replay chunk independently of analytics events","security":[{"writeKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["recordingId","tabId","anonymousId","sequence","startedAt","events"],"properties":{"recordingId":{"type":"string","pattern":"^[a-zA-Z0-9_-]{8,80}$"},"tabId":{"type":"string","pattern":"^[a-zA-Z0-9_-]{8,80}$"},"anonymousId":{"type":"string","minLength":1,"maxLength":200},"userId":{"type":"string","minLength":1,"maxLength":200},"sequence":{"type":"integer","minimum":0,"maximum":359},"startedAt":{"type":"integer","description":"Recording start in epoch milliseconds"},"events":{"type":"array","minItems":1,"maxItems":2000,"items":{"type":"object","required":["type","timestamp","data"],"properties":{"type":{"type":"integer","minimum":0,"maximum":6},"timestamp":{"type":"integer"},"data":{}}}},"writeKey":{"type":"string"}}}}}},"responses":{"202":{"description":"Queued; not yet persisted","content":{"application/json":{"schema":{"type":"object","properties":{"queued":{"type":"boolean"}}}}}},"400":{"description":"invalid chunk","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid write key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"chunk exceeds size limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"tenant replay ingress budget exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/events/names":{"get":{"operationId":"listEventNames","summary":"Event names with all-time counts (top 300)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/taxonomy":{"get":{"operationId":"getTaxonomy","summary":"Recommended event catalog for a vertical (default: the tenant’s)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"type":"string","enum":["saas","ecommerce","content"]},"description":"override vertical"}]}},"/api/presets/apply":{"post":{"operationId":"applyPresets","summary":"Create the preset segments / default attributes that are missing (idempotent)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/reports/{name}":{"get":{"operationId":"runReport","summary":"Run a founder report","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"}}}},"400":{"description":"missing parameter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"unknown report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"overview, trends, retention, cohorts (weeks), sources (dim, touch), transitions, pages, page (path: one page in depth — tiles vs previous period, daily series, referrers, previous/next pages, events on it), events, event-props (event), segment-sizes, segment-entries (segment), segment-compare (segment), ai-visibility.","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","enum":["overview","trends","retention","cohorts","sources","transitions","pages","page","segment-sizes","segment-entries","segment-compare","events","event-props","ai-visibility"]},"description":"report name"},{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":730,"default":30},"description":"Period = the last N whole UTC days including today."},{"name":"dim","in":"query","required":false,"schema":{"type":"string","enum":["channel","referrer","utm_source","utm_medium","utm_campaign","landing","country","device","browser","os"],"default":"channel"},"description":"sources only"},{"name":"touch","in":"query","required":false,"schema":{"type":"string","enum":["first","last"],"default":"last"},"description":"sources only"},{"name":"event","in":"query","required":false,"schema":{"type":"string"},"description":"event-props only"},{"name":"path","in":"query","required":false,"schema":{"type":"string"},"description":"page only: the page path, e.g. /blog/post"},{"name":"segment","in":"query","required":false,"schema":{"type":"string"},"description":"segment-entries / segment-compare"},{"name":"weeks","in":"query","required":false,"schema":{"type":"integer","default":8},"description":"cohorts only"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500},"description":"row cap"}]}},"/api/site":{"get":{"operationId":"getSite","summary":"The host that served most page views in the last 90 days (for linking paths back to the live site)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"host":{"type":"string","nullable":true},"sql":{"type":"string"},"ms":{"type":"integer"}}}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/overview":{"get":{"operationId":"getOverview","summary":"Legacy totals + 28-day daily series","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/users":{"get":{"operationId":"listUsers","summary":"Page through user_vectors","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"$ref":"#/components/schemas/UserVector"}},"total":{"type":"integer"}}}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"default":50},"description":""},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0},"description":""},{"name":"sort","in":"query","required":false,"schema":{"type":"string","default":"last_seen"},"description":"any user_vectors column"},{"name":"dir","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"description":""},{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"ILIKE match on user_id / email / name"}]}},"/api/users/{id}":{"get":{"operationId":"getUser","summary":"One person: vector, identities, traits, last 200 events, sessions, segments","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"unknown user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"any external id (anon/user) or canonical id"}]},"delete":{"operationId":"eraseUser","summary":"GDPR erasure — IRREVERSIBLE: delete every row about this person for ALL ids that resolve to them, tombstone the ids (late events dropped, replay/restore skip them) and rewrite the raw JSONL log without them","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erasure"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"unknown user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Removes the person from events, identities, profiles, sessions, user_vectors, segment_members, deliveries and the suppression list (their email). Tombstones live in the `erasures` table. The raw log is rewritten inline for small logs (`raw.status: purged`) or in the background (`queued`). Idempotent: an already-erased id answers 200 with `already_erased: true`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"any external id of the person, or the canonical id"}]}},"/api/attributes":{"get":{"operationId":"listAttributes","summary":"List declared attributes","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AttributeDef"}}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"upsertAttribute","summary":"Create or replace an attribute (takes effect at the next rebuild — call POST /api/rebuild)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttributeDef"}}}}}},"/api/attributes/{name}":{"delete":{"operationId":"deleteAttribute","summary":"Delete an attribute","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":""}]}},"/api/attributes/sql":{"get":{"operationId":"attributesSql","summary":"The compiled single-pass SQL that builds user_vectors","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/rebuild":{"post":{"operationId":"rebuild","summary":"Rebuild sessions → user_vectors → segment_members now","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/segments":{"get":{"operationId":"listSegments","summary":"List segments with current size","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Segment"}}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createSegment","summary":"Create a segment (membership materialised at the next rebuild)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","def"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"def":{"$ref":"#/components/schemas/SegmentDef"}}}}}}}},"/api/segments/preview":{"post":{"operationId":"previewSegment","summary":"Evaluate a SegmentDef without saving: count + 20 sample users + compiled WHERE","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SegmentDef"}}}}}},"/api/segments/{id}":{"put":{"operationId":"updateSegment","summary":"Update name and/or definition of a segment and rebuild membership (mirrors MCP update_segment)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Segment"}}}},"400":{"description":"bad definition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"unknown segment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SegmentUpdate"}}}}},"delete":{"operationId":"deleteSegment","summary":"Delete a segment and its members","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}]}},"/api/segments/{id}/members":{"get":{"operationId":"segmentMembers","summary":"Current members (up to 500) with entered_at","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserVector"}}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}]}},"/api/campaigns":{"get":{"operationId":"listCampaigns","summary":"List campaigns with sent/failed counts","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Campaign"}}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createCampaign","summary":"Create or replace a campaign","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignInput"}}}}}},"/api/campaigns/{id}/run":{"post":{"operationId":"runCampaign","summary":"Run a campaign. dryRun=true (the default) reports eligible recipients without sending. dryRun=false REALLY SENDS email (rate limited; suppressed addresses skipped; every send recorded as a $email_sent system event).","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignRun"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"unknown campaign","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"dryRun":{"type":"boolean","default":true},"limit":{"type":"integer","minimum":1,"maximum":10000}}}}}}}},"/api/campaigns/{id}":{"delete":{"operationId":"deleteCampaign","summary":"Delete a campaign","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}]}},"/api/webhooks":{"get":{"operationId":"listWebhooks","summary":"List segment enter/exit webhooks with sent/failed counts","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createWebhook","summary":"Create or replace a webhook (active defaults to false; test it with /test first)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"400":{"description":"bad url / body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"unknown segment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"id not available","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInput"}}}}}},"/api/webhooks/{id}":{"put":{"operationId":"updateWebhook","summary":"Update any subset of a webhook’s fields","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"unknown webhook","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInput"}}}}},"delete":{"operationId":"deleteWebhook","summary":"Delete a webhook (delivery history is kept)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}]}},"/api/webhooks/{id}/test":{"post":{"operationId":"testWebhook","summary":"Send one synthetic payload (test: true) now, bypassing the queue; returns status and latency","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTest"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"unknown webhook","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}]}},"/api/webhooks/{id}/deliveries":{"get":{"operationId":"listWebhookDeliveries","summary":"Delivery attempts of a webhook, newest first","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"unknown webhook","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"default":100},"description":""},{"name":"user_id","in":"query","required":false,"schema":{"type":"string"},"description":"only this user"}]}},"/api/suppressions":{"get":{"operationId":"listSuppressions","summary":"Addresses that are never emailed (unsubscribed, bounced 3x, manual)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Suppression"}}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"addSuppression","summary":"Suppress an address (idempotent, lower-cased)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Suppression"}}}}}},"/api/suppressions/{email}":{"delete":{"operationId":"removeSuppression","summary":"Remove an address from the suppression list","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"email","in":"path","required":true,"schema":{"type":"string"},"description":""}]}},"/api/analytics/lifecycle":{"get":{"operationId":"lifecycle","summary":"Acquisition channels, independent lifecycle stages, ordered pairwise connections, return visits and recorded revenue","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}},{"in":"query","name":"registration","schema":{"type":"string","maxLength":200}},{"in":"query","name":"activation","schema":{"type":"string","maxLength":200}},{"in":"query","name":"purchase","schema":{"type":"string","maxLength":200}}]}},"/api/analytics/landscape":{"get":{"operationId":"landscape","summary":"Traffic quality and the 3D explorer data: people per UTC day × hour × class (people, suspected automation, server-side only), and every person once at the furthest stage reached by first-touch channel","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}},{"in":"query","name":"registration","schema":{"type":"string","maxLength":200}},{"in":"query","name":"activation","schema":{"type":"string","maxLength":200}}]}},"/api/analytics/audiences":{"get":{"operationId":"audiences","summary":"Saved segments with current members and email reach (email | blocked | none), the email campaigns and webhooks wired to each with deliveries in the period, and on-site layer impressions","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}}]}},"/api/analytics/paths":{"get":{"operationId":"paths","summary":"Path flow for the 3D explorer: each counted person's first visit in the period as page sections (or pages) per step, with links between steps, exits (left / continued) and one row per person; layered by goal outcome or first-touch channel","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}},{"in":"query","name":"goal","schema":{"type":"string","maxLength":200},"description":"Outcome event; default: the first recorded of signup_completed, …, $identify"},{"in":"query","name":"depth","schema":{"type":"integer","minimum":2,"maximum":6,"default":4}},{"in":"query","name":"by","schema":{"enum":["section","page"],"default":"section"}},{"in":"query","name":"split","schema":{"enum":["outcome","channel"],"default":"outcome"}},{"in":"query","name":"width","schema":{"type":"integer","minimum":3,"maximum":12,"default":7},"description":"Nodes per step before the rest share Other pages"}]}},"/api/analytics/journey-flow":{"get":{"operationId":"journeyFlow","summary":"Journey funnel as a flow: a saved journey (id) or ad-hoc steps, with people per step and first-touch channel, mature drop-offs (left), people still inside the window (pending) and median time between steps","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}},{"in":"query","name":"id","schema":{"type":"string"},"description":"Saved journey definition"},{"in":"query","name":"version","schema":{"type":"integer","minimum":1}},{"in":"query","name":"steps","schema":{"type":"string","maxLength":2000},"description":"Comma-separated event names; page:/text is a page view whose path contains the text"},{"in":"query","name":"horizon","schema":{"type":"integer","minimum":1,"maximum":90,"default":7},"description":"Days after entry for ad-hoc steps"}]}},"/api/analytics/lifelines":{"get":{"operationId":"lifelines","summary":"Time to value for the 3D explorer: everyone whose first anchor (a sign-up event, or $first_visit) falls in the period, with the first time of each milestone after it, last activity, first-touch channel, and how many were still active after 1 minute, 1 hour, 1 day, 1 week and 30 days","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}},{"in":"query","name":"anchor","schema":{"type":"string","maxLength":200},"description":"Event name or $first_visit; default: the first recorded sign-up event with at least 20 people in the period, else $first_visit"},{"in":"query","name":"steps","schema":{"type":"string","maxLength":2000},"description":"Comma-separated milestone events (at most 6); default: saved-journey events, then the most common"}]}},"/api/analytics/galaxy":{"get":{"operationId":"galaxy","summary":"Page galaxy for the 3D explorer: every page visited in the period with visitors, views, entries, exits, goal reached after viewing it, track events fired on it, grouped by section, plus the busiest page-to-page moves inside visits","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}},{"in":"query","name":"goal","schema":{"type":"string","maxLength":200},"description":"Goal event; default: the first recorded of signup_completed, …, $identify"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":20,"maximum":600,"default":300},"description":"Pages drawn as stars; the rest are counted in their section"}]}},"/api/lab/market":{"get":{"operationId":"labMarket","summary":"Lab: opportunities (detail pages of the busiest sections) with viewers, people per action fired on them, responses linked through shared *_id values, and co-viewed pairs","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}},{"in":"query","name":"districts","schema":{"type":"integer","minimum":1,"maximum":8,"default":5}},{"in":"query","name":"items","schema":{"type":"integer","minimum":5,"maximum":120,"default":48}}]}},"/api/lab/globe":{"get":{"operationId":"labGlobe","summary":"Lab: people, suspected automation, crawler requests, goal and last-hour activity by country, plus people per country and day","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}},{"in":"query","name":"goal","schema":{"type":"string","maxLength":200}}]}},"/api/lab/canyon":{"get":{"operationId":"labCanyon","summary":"Lab: first-visit cohorts (days or weeks) by periods since, people active in each, and the average of complete cohorts","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"in":"query","name":"unit","schema":{"enum":["auto","day","week"],"default":"auto"}},{"in":"query","name":"periods","schema":{"type":"integer","minimum":3,"maximum":26}}]}},"/api/lab/live":{"get":{"operationId":"labLive","summary":"Lab: the latest events (time received, kind, name, section, person hash, country) since a cursor, for the live event rain","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"in":"query","name":"minutes","schema":{"type":"integer","minimum":1,"maximum":1440,"default":180}},{"in":"query","name":"since","schema":{"type":"integer","minimum":0},"description":"Cursor (ms) from the previous response"}]}},"/api/settings/traffic":{"get":{"operationId":"trafficSettings","summary":"Whether reports count suspected automation (default: no)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"setTrafficSettings","summary":"Count suspected automation in reports or leave it out (write scope). Segments never include it.","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["include_automation"],"properties":{"include_automation":{"type":"boolean"}},"additionalProperties":false}}}}}},"/api/analytics/funnel":{"post":{"operationId":"funnel","summary":"Sequential funnel over event names: step k = first occurrence after step k-1, optionally within a window of the first step; per-step users, rate, dropped, median_seconds; optional breakdown by a first-step property","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Funnel"}}}},"400":{"description":"fewer than 2 steps, consecutive duplicate steps, bad window/breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["steps"],"properties":{"steps":{"type":"array","items":{"type":"string"},"minItems":2,"maxItems":8,"description":"no two consecutive steps may be the same event"},"days":{"type":"integer","default":30},"window":{"type":"string","pattern":"^\\d+[mhdw]$","description":"max time from the first to the last step, e.g. 7d"},"breakdown":{"type":"string","description":"path | referrer | country | device | props.<key>"}}}}}}}},"/api/analytics/retention":{"post":{"operationId":"retention","summary":"Weekly cohort retention (cohort × week_n × users)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"weeks":{"type":"integer","default":8}}}}}}}},"/api/sql":{"post":{"operationId":"runSql","summary":"Read-only SQL against the tenant DuckDB (wrapped in SELECT * FROM (…) LIMIT limit; write keywords rejected)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SqlResult"}}}},"400":{"description":"rejected or engine error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sql"],"properties":{"sql":{"type":"string","maxLength":20000},"limit":{"type":"integer","maximum":10000,"default":500}}}}}}}},"/api/dashboards/templates":{"get":{"operationId":"listDashboardTemplates","summary":"List dashboard templates (id, name, description, params with defaults); instantiate one with POST /api/dashboards {template, params?, name?}","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","additionalProperties":true}}}}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/dashboards":{"get":{"operationId":"listDashboards","summary":"List dashboards","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Dashboard"}}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createDashboard","summary":"Create a dashboard from a widget list, or from a template ({template, params?, name?} — see GET /api/dashboards/templates)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Dashboard"}}}},"400":{"description":"bad widget / unknown template","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/DashboardInput"},{"type":"object","required":["template"],"properties":{"template":{"type":"string","enum":["ai-visibility","acquisition","content","conversion-intent","accounts"]},"params":{"type":"object","additionalProperties":true},"name":{"type":"string"}}}]}}}}}},"/api/dashboards/{id}":{"get":{"operationId":"getDashboard","summary":"Get a dashboard","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Dashboard"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"unknown dashboard","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}]},"put":{"operationId":"updateDashboard","summary":"Replace name/description/widgets","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Dashboard"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"unknown dashboard","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardInput"}}}}},"delete":{"operationId":"deleteDashboard","summary":"Delete a dashboard","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}},"400":{"description":"bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}]}},"/api/dashboards/{id}/data":{"get":{"operationId":"dashboardData","summary":"Evaluate every widget for a period","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"unknown dashboard","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""},{"name":"period","in":"query","required":false,"schema":{"type":"integer","default":30},"description":"days"}]}},"/api/keys":{"get":{"operationId":"listApiKeys","summary":"List API keys (id, name, prefix, scope, created / last used / revoked) — admin scope; no secrets","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"admin scope required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createApiKey","summary":"Create a scoped API key — admin scope. The plaintext `key` is returned once and only its SHA-256 is stored.","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiKey"},{"type":"object","properties":{"key":{"type":"string","description":"sk_<r|w|a>_… — shown once"}}}]}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"admin scope required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","scope"],"properties":{"name":{"type":"string","maxLength":100},"scope":{"type":"string","enum":["read","write","admin"]}}}}}}}},"/api/keys/{id}":{"delete":{"operationId":"revokeApiKey","summary":"Revoke a key (it stops resolving immediately; the row is kept) — admin scope","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"id":{"type":"string"}}}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"admin scope required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"unknown key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}]}},"/api/keys/rotate-write-key":{"post":{"operationId":"rotateWriteKey","summary":"Issue a fresh collector write key (SDK / POST /v1/* key) — admin scope. The old key stops at once, in every collector process (Redis mirror); redeploy the tracking snippet with the new key.","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"write_key":{"type":"string"}}}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"admin scope required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/audit":{"get":{"operationId":"readAuditLog","summary":"Audit log, newest first — admin scope: every mutating REST call, MCP tool call, GDPR erasure and real campaign send (principal = key id, scope, surface, action, target, ok, ms, ip_hash, redacted detail); 180-day retention","security":[{"bearer":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AuditRow"}}}}},"401":{"description":"invalid api key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"admin scope required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":730,"default":30},"description":"Period = the last N whole UTC days including today."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"default":200},"description":""},{"name":"principal","in":"query","required":false,"schema":{"type":"string"},"description":"only this key id"},{"name":"action","in":"query","required":false,"schema":{"type":"string"},"description":"only this route / tool name"}]}},"/api/openapi.json":{"get":{"operationId":"openapi","summary":"This document","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{}}}}}}}}}