{
  "components": {
    "parameters": {
      "end": {
        "description": "Range end (RFC 3339); defaults to now.",
        "in": "query",
        "name": "end",
        "schema": {
          "format": "date-time",
          "type": "string"
        }
      },
      "limit": {
        "in": "query",
        "name": "limit",
        "schema": {
          "default": 100,
          "maximum": 1000,
          "minimum": 1,
          "type": "integer"
        }
      },
      "offset": {
        "in": "query",
        "name": "offset",
        "schema": {
          "default": 0,
          "minimum": 0,
          "type": "integer"
        }
      },
      "projectUUID": {
        "in": "path",
        "name": "project_uuid",
        "required": true,
        "schema": {
          "format": "uuid",
          "type": "string"
        }
      },
      "start": {
        "description": "Range start (RFC 3339); defaults to 30 days ago.",
        "in": "query",
        "name": "start",
        "schema": {
          "format": "date-time",
          "type": "string"
        }
      }
    },
    "schemas": {
      "AnalyticsMetrics": {
        "properties": {
          "avg_events_per_user": {
            "type": "number"
          },
          "events_today": {
            "minimum": 0,
            "type": "integer"
          },
          "total_events": {
            "minimum": 0,
            "type": "integer"
          },
          "total_users": {
            "minimum": 0,
            "type": "integer"
          },
          "unique_users_today": {
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "avg_events_per_user",
          "events_today",
          "total_events",
          "total_users",
          "unique_users_today"
        ],
        "type": "object"
      },
      "AuditEntry": {
        "properties": {
          "action": {
            "type": "string"
          },
          "actor_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "ip_address": {
            "type": "string"
          },
          "metadata": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Action-specific details, all string valued.",
            "type": "object"
          },
          "organization_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "target_type": {
            "type": "string"
          },
          "target_uuid": {
            "type": "string"
          }
        },
        "required": [
          "action",
          "actor_uuid",
          "created_at",
          "ip_address",
          "organization_uuid",
          "target_type",
          "target_uuid"
        ],
        "type": "object"
      },
      "Board": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "created_by": {
            "format": "uuid",
            "type": "string"
          },
          "definition": {
            "$ref": "#/components/schemas/BoardDefinition"
          },
          "description": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "project_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "uuid": {
            "format": "uuid",
            "type": "string"
          },
          "version": {
            "description": "How many times the board has been saved, starting at 1. Send it back with an update; an update made from an older version is refused with 409.",
            "minimum": 0,
            "type": "integer"
          },
          "visibility": {
            "description": "project: every member of the organization sees the board. private: only its creator does; to anyone else it does not exist (404).",
            "type": "string"
          },
          "widget_count": {
            "type": "integer"
          }
        },
        "required": [
          "created_at",
          "created_by",
          "definition",
          "description",
          "name",
          "project_uuid",
          "updated_at",
          "uuid",
          "version",
          "visibility",
          "widget_count"
        ],
        "type": "object"
      },
      "BoardDefinition": {
        "properties": {
          "filters": {
            "items": {
              "$ref": "#/components/schemas/Filter"
            },
            "type": "array"
          },
          "match": {
            "type": "string"
          },
          "range": {
            "type": "string"
          },
          "timezone": {
            "type": "string"
          },
          "widgets": {
            "items": {
              "$ref": "#/components/schemas/Widget"
            },
            "type": "array"
          }
        },
        "required": [
          "match"
        ],
        "type": "object"
      },
      "BoardSummary": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "created_by": {
            "format": "uuid",
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "project_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "uuid": {
            "format": "uuid",
            "type": "string"
          },
          "version": {
            "description": "How many times the board has been saved, starting at 1. Send it back with an update; an update made from an older version is refused with 409.",
            "minimum": 0,
            "type": "integer"
          },
          "visibility": {
            "description": "project: every member of the organization sees the board. private: only its creator does; to anyone else it does not exist (404).",
            "type": "string"
          },
          "widget_count": {
            "type": "integer"
          }
        },
        "required": [
          "created_at",
          "created_by",
          "description",
          "name",
          "project_uuid",
          "updated_at",
          "uuid",
          "version",
          "visibility",
          "widget_count"
        ],
        "type": "object"
      },
      "BoardWidgetResult": {
        "properties": {
          "end": {
            "format": "date-time",
            "type": "string"
          },
          "flow": {
            "$ref": "#/components/schemas/FlowResult"
          },
          "funnel": {
            "$ref": "#/components/schemas/FunnelResult"
          },
          "retention": {
            "$ref": "#/components/schemas/RetentionResult"
          },
          "start": {
            "format": "date-time",
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "widget_id": {
            "type": "string"
          }
        },
        "required": [
          "end",
          "start",
          "type",
          "widget_id"
        ],
        "type": "object"
      },
      "Breakdown": {
        "properties": {
          "property": {
            "type": "string"
          },
          "scope": {
            "type": "string"
          }
        },
        "required": [
          "property",
          "scope"
        ],
        "type": "object"
      },
      "ClientContext": {
        "properties": {
          "app": {
            "$ref": "#/components/schemas/ContextApp"
          },
          "campaign": {
            "$ref": "#/components/schemas/ContextCampaign"
          },
          "device": {
            "$ref": "#/components/schemas/ContextDevice"
          },
          "library": {
            "$ref": "#/components/schemas/ContextLibrary"
          },
          "locale": {
            "type": "string"
          },
          "network": {
            "$ref": "#/components/schemas/ContextNetwork"
          },
          "os": {
            "$ref": "#/components/schemas/ContextOS"
          },
          "timezone": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "Cohort": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "created_by": {
            "format": "uuid",
            "type": "string"
          },
          "definition": {
            "$ref": "#/components/schemas/CohortDefinition"
          },
          "description": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "project_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "uuid": {
            "format": "uuid",
            "type": "string"
          },
          "version": {
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "created_at",
          "created_by",
          "definition",
          "description",
          "name",
          "project_uuid",
          "updated_at",
          "uuid",
          "version"
        ],
        "type": "object"
      },
      "CohortCount": {
        "properties": {
          "as_of": {
            "description": "When membership was evaluated. Cohorts are computed from current data on every request.",
            "format": "date-time",
            "type": "string"
          },
          "count": {
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "as_of",
          "count"
        ],
        "type": "object"
      },
      "CohortDefinition": {
        "properties": {
          "match": {
            "description": "all (every rule) or any (at least one rule).",
            "type": "string"
          },
          "rules": {
            "items": {
              "$ref": "#/components/schemas/CohortRule"
            },
            "type": "array"
          },
          "schema": {
            "description": "The definition language version: cohort/1.",
            "type": "string"
          }
        },
        "required": [
          "match",
          "schema"
        ],
        "type": "object"
      },
      "CohortFlow": {
        "properties": {
          "cohort_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "direction": {
            "type": "string"
          },
          "end": {
            "format": "date-time",
            "type": "string"
          },
          "event": {
            "type": "string"
          },
          "exclude": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "path": {
            "items": {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            "type": "array"
          },
          "start": {
            "format": "date-time",
            "type": "string"
          },
          "window_hours": {
            "type": "integer"
          }
        },
        "required": [
          "direction",
          "end",
          "event",
          "start",
          "window_hours"
        ],
        "type": "object"
      },
      "CohortMembers": {
        "properties": {
          "as_of": {
            "format": "date-time",
            "type": "string"
          },
          "count": {
            "minimum": 0,
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "members": {
            "items": {
              "$ref": "#/components/schemas/User"
            },
            "type": "array"
          },
          "offset": {
            "type": "integer"
          }
        },
        "required": [
          "as_of",
          "count",
          "limit",
          "offset"
        ],
        "type": "object"
      },
      "CohortRule": {
        "properties": {
          "cohort_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "count": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CohortCount"
              }
            ],
            "description": "gte (at least), lte (at most; 0 includes users without the event) or eq (exactly) matching events in the window. Defaults to at least 1."
          },
          "event": {
            "type": "string"
          },
          "filter_match": {
            "type": "string"
          },
          "filters": {
            "items": {
              "$ref": "#/components/schemas/Filter"
            },
            "type": "array"
          },
          "flow": {
            "$ref": "#/components/schemas/CohortFlow"
          },
          "match": {
            "type": "string"
          },
          "negate": {
            "description": "Every user with an event in the project who does not match the rule.",
            "type": "boolean"
          },
          "rules": {
            "items": {
              "$ref": "#/components/schemas/CohortRule"
            },
            "type": "array"
          },
          "steps": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "type": {
            "description": "group (match + rules), event (event, filters, count, window), property (user-scope filters on the profile), first_seen (window the first event falls in), sequence (steps in order within window_hours, inside window, by the funnel rules), cohort (cohort_uuid of another cohort of the project, at most 3 references deep).",
            "type": "string"
          },
          "window": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CohortWindow"
              }
            ],
            "description": "The window an event or sequence rule reads; defaults to the last 30 days. Windows are [start, end)."
          },
          "window_hours": {
            "type": "integer"
          }
        },
        "required": [
          "type"
        ],
        "type": "object"
      },
      "CohortWindow": {
        "properties": {
          "end": {
            "format": "date-time",
            "type": "string"
          },
          "last_days": {
            "description": "The last n days before the evaluation time. Use this or start and end.",
            "type": "integer"
          },
          "start": {
            "format": "date-time",
            "type": "string"
          }
        },
        "type": "object"
      },
      "ConfirmPasswordReset": {
        "properties": {
          "new_password": {
            "type": "string"
          },
          "token": {
            "type": "string"
          }
        },
        "required": [
          "new_password",
          "token"
        ],
        "type": "object"
      },
      "ConsentRecord": {
        "properties": {
          "actor": {
            "type": "string"
          },
          "purpose": {
            "type": "string"
          },
          "recorded_at": {
            "format": "date-time",
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "state": {
            "type": "string"
          }
        },
        "required": [
          "actor",
          "purpose",
          "recorded_at",
          "source",
          "state"
        ],
        "type": "object"
      },
      "ContextApp": {
        "properties": {
          "build": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "version": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "ContextCampaign": {
        "properties": {
          "content": {
            "type": "string"
          },
          "medium": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "term": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "ContextDevice": {
        "properties": {
          "id": {
            "type": "string"
          },
          "manufacturer": {
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "type": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "ContextLibrary": {
        "properties": {
          "name": {
            "type": "string"
          },
          "version": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "ContextNetwork": {
        "properties": {
          "bluetooth": {
            "type": "boolean"
          },
          "carrier": {
            "type": "string"
          },
          "cellular": {
            "type": "boolean"
          },
          "wifi": {
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "ContextOS": {
        "properties": {
          "name": {
            "type": "string"
          },
          "version": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "DashboardInitResponse": {
        "properties": {
          "events": {
            "items": {
              "$ref": "#/components/schemas/Event"
            },
            "type": "array"
          },
          "metrics": {
            "$ref": "#/components/schemas/AnalyticsMetrics"
          },
          "overview": {
            "$ref": "#/components/schemas/TrafficOverview"
          },
          "time_series": {
            "items": {
              "$ref": "#/components/schemas/TimeSeriesData"
            },
            "type": "array"
          },
          "top_events": {
            "items": {
              "$ref": "#/components/schemas/TopEvents"
            },
            "type": "array"
          },
          "users": {
            "items": {
              "$ref": "#/components/schemas/User"
            },
            "type": "array"
          }
        },
        "type": "object"
      },
      "ErasureReport": {
        "properties": {
          "physical_purge": {
            "type": "string"
          },
          "purge": {
            "$ref": "#/components/schemas/PurgeResult"
          },
          "status": {
            "type": "string"
          },
          "suppression": {
            "type": "string"
          },
          "user_uuid": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "physical_purge",
          "purge",
          "status",
          "suppression",
          "user_uuid"
        ],
        "type": "object"
      },
      "ErrorResponse": {
        "properties": {
          "error": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ],
        "type": "object"
      },
      "Event": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "organization_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "parent": {
            "$ref": "#/components/schemas/EventParent"
          },
          "parent_name": {
            "type": "string"
          },
          "project": {
            "$ref": "#/components/schemas/Project"
          },
          "project_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "properties": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "The flat string map analytics filters and groups on: nested objects become dotted keys, numbers and booleans are stringified, strings are cut at 4096 bytes.",
            "type": "object"
          },
          "properties_exact": {
            "additionalProperties": true,
            "description": "The properties object exactly as sent (numbers with their own text, booleans, nulls, arrays, nested objects, uncut strings). Present only when it differs from properties; absent means properties is already exact. See docs/EVENT_PROPERTIES.md.",
            "type": "object"
          },
          "type": {
            "description": "track for custom events, page_view for navigation.",
            "enum": [
              "track",
              "identify",
              "page_view"
            ],
            "type": "string"
          },
          "user": {
            "$ref": "#/components/schemas/User"
          },
          "user_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "uuid": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "organization_uuid",
          "project_uuid",
          "type"
        ],
        "type": "object"
      },
      "EventData": {
        "properties": {
          "created_at": {
            "description": "When the event happened (RFC 3339), on the device's clock. Absent means when the api received it; a time more than an hour ahead is replaced by the receive time.",
            "format": "date-time",
            "type": "string"
          },
          "group_id": {
            "description": "Required when type is group.",
            "type": "string"
          },
          "message_id": {
            "description": "The SDK's id for this event, a UUID made once per call and kept across retries. The api deduplicates on it for 24 hours: a resent item with the same id and content is answered as accepted and stored once; the same id with different content is refused with 409 event_id_conflict. Forwarded to IForevents Cloud destinations.",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "previous_id": {
            "description": "Required when type is alias.",
            "type": "string"
          },
          "properties": {
            "additionalProperties": true,
            "type": "object"
          },
          "type": {
            "description": "Defaults to track. page_view and screen are stored as page views; group and alias are not stored or counted as events and only reach the Cloud destinations, like identify.",
            "enum": [
              "track",
              "page_view",
              "screen",
              "group",
              "alias"
            ],
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "name",
          "type"
        ],
        "type": "object"
      },
      "EventParent": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "events": {
            "items": {
              "$ref": "#/components/schemas/Event"
            },
            "type": "array"
          },
          "name": {
            "type": "string"
          },
          "project": {
            "$ref": "#/components/schemas/Project"
          },
          "project_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "uuid": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "name",
          "project_uuid"
        ],
        "type": "object"
      },
      "EventParentProperties": {
        "properties": {
          "name": {
            "type": "string"
          },
          "properties": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "name"
        ],
        "type": "object"
      },
      "EventParentPropertiesValues": {
        "properties": {
          "name": {
            "type": "string"
          },
          "property": {
            "type": "string"
          },
          "values": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "name",
          "property"
        ],
        "type": "object"
      },
      "Filter": {
        "properties": {
          "operator": {
            "type": "string"
          },
          "property": {
            "type": "string"
          },
          "scope": {
            "description": "event (the event's own properties), user (the user's current profile) or cohort (membership: property is a saved cohort's uuid, operator is in or not_in, no values).",
            "type": "string"
          },
          "values": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "operator",
          "property",
          "scope"
        ],
        "type": "object"
      },
      "FilterGroup": {
        "properties": {
          "filters": {
            "items": {
              "$ref": "#/components/schemas/Filter"
            },
            "type": "array"
          },
          "match": {
            "type": "string"
          }
        },
        "required": [
          "match"
        ],
        "type": "object"
      },
      "FlowEdge": {
        "properties": {
          "depth": {
            "type": "integer"
          },
          "from": {
            "type": "string"
          },
          "to": {
            "type": "string"
          },
          "to_other": {
            "type": "boolean"
          },
          "users": {
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "depth",
          "from",
          "to",
          "to_other",
          "users"
        ],
        "type": "object"
      },
      "FlowLevel": {
        "properties": {
          "depth": {
            "type": "integer"
          },
          "nodes": {
            "items": {
              "$ref": "#/components/schemas/FlowNode"
            },
            "type": "array"
          },
          "suppressed": {
            "description": "Events of this level that fewer than min_users users reached; their users are in the Other node.",
            "type": "integer"
          }
        },
        "required": [
          "depth",
          "suppressed"
        ],
        "type": "object"
      },
      "FlowNode": {
        "properties": {
          "dropoff": {
            "minimum": 0,
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "other": {
            "type": "boolean"
          },
          "users": {
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "dropoff",
          "name",
          "other",
          "users"
        ],
        "type": "object"
      },
      "FlowResult": {
        "properties": {
          "direction": {
            "type": "string"
          },
          "edges": {
            "items": {
              "$ref": "#/components/schemas/FlowEdge"
            },
            "type": "array"
          },
          "event": {
            "type": "string"
          },
          "exclude": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "levels": {
            "items": {
              "$ref": "#/components/schemas/FlowLevel"
            },
            "type": "array"
          },
          "min_users": {
            "type": "integer"
          },
          "observed_until": {
            "format": "date-time",
            "type": "string"
          },
          "open_window_users": {
            "minimum": 0,
            "type": "integer"
          },
          "steps": {
            "type": "integer"
          },
          "top_k": {
            "type": "integer"
          },
          "users": {
            "minimum": 0,
            "type": "integer"
          },
          "window_hours": {
            "type": "integer"
          }
        },
        "required": [
          "direction",
          "event",
          "min_users",
          "observed_until",
          "open_window_users",
          "steps",
          "top_k",
          "users",
          "window_hours"
        ],
        "type": "object"
      },
      "FunnelBreakdown": {
        "properties": {
          "attribution": {
            "description": "entry_event (the value on the step-1 event) or current_profile.",
            "type": "string"
          },
          "limit": {
            "type": "integer"
          },
          "property": {
            "type": "string"
          },
          "scope": {
            "type": "string"
          },
          "series": {
            "items": {
              "$ref": "#/components/schemas/FunnelSeries"
            },
            "type": "array"
          }
        },
        "required": [
          "attribution",
          "limit",
          "property",
          "scope"
        ],
        "type": "object"
      },
      "FunnelDrillResult": {
        "properties": {
          "counting": {
            "type": "string"
          },
          "has_more": {
            "type": "boolean"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "status": {
            "type": "string"
          },
          "step": {
            "type": "integer"
          },
          "total_units": {
            "minimum": 0,
            "type": "integer"
          },
          "total_users": {
            "minimum": 0,
            "type": "integer"
          },
          "users": {
            "items": {
              "$ref": "#/components/schemas/FunnelDrillUser"
            },
            "type": "array"
          }
        },
        "required": [
          "counting",
          "has_more",
          "limit",
          "offset",
          "status",
          "step",
          "total_units",
          "total_users"
        ],
        "type": "object"
      },
      "FunnelDrillUser": {
        "properties": {
          "entry": {
            "format": "date-time",
            "type": "string"
          },
          "step_times": {
            "items": {
              "format": "date-time",
              "type": "string"
            },
            "type": "array"
          },
          "units": {
            "minimum": 0,
            "type": "integer"
          },
          "user_uuid": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "entry",
          "units",
          "user_uuid"
        ],
        "type": "object"
      },
      "FunnelExclusion": {
        "properties": {
          "event": {
            "type": "string"
          },
          "filters": {
            "items": {
              "$ref": "#/components/schemas/Filter"
            },
            "type": "array"
          },
          "from_step": {
            "description": "1-based step the exclusion starts after; defaults to 1.",
            "type": "integer"
          },
          "match": {
            "type": "string"
          },
          "to_step": {
            "description": "1-based step the exclusion ends before; defaults to the last step.",
            "type": "integer"
          }
        },
        "required": [
          "event"
        ],
        "type": "object"
      },
      "FunnelHistogramBucket": {
        "properties": {
          "max_seconds": {
            "type": "integer"
          },
          "min_seconds": {
            "type": "integer"
          },
          "users": {
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "max_seconds",
          "min_seconds",
          "users"
        ],
        "type": "object"
      },
      "FunnelResult": {
        "properties": {
          "breakdown": {
            "$ref": "#/components/schemas/FunnelBreakdown"
          },
          "counting": {
            "type": "string"
          },
          "excluded_users": {
            "description": "Entrants removed by exclusions; they are in no step count.",
            "minimum": 0,
            "type": "integer"
          },
          "immature_users": {
            "minimum": 0,
            "type": "integer"
          },
          "observed_until": {
            "format": "date-time",
            "type": "string"
          },
          "overall_conversion_rate": {
            "type": "number"
          },
          "steps": {
            "items": {
              "$ref": "#/components/schemas/FunnelStep"
            },
            "type": "array"
          },
          "time_to_convert": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FunnelTimeToConvert"
              }
            ],
            "description": "Entry to last step, over mature users who completed; null when there is none."
          },
          "total_completed": {
            "minimum": 0,
            "type": "integer"
          },
          "total_entered": {
            "minimum": 0,
            "type": "integer"
          },
          "window_hours": {
            "type": "integer"
          }
        },
        "required": [
          "counting",
          "excluded_users",
          "immature_users",
          "observed_until",
          "total_completed",
          "total_entered",
          "window_hours"
        ],
        "type": "object"
      },
      "FunnelSeries": {
        "properties": {
          "immature_users": {
            "minimum": 0,
            "type": "integer"
          },
          "key": {
            "type": "string"
          },
          "other": {
            "description": "True for the one series that sums every key past the limit.",
            "type": "boolean"
          },
          "overall_conversion_rate": {
            "type": "number"
          },
          "steps": {
            "items": {
              "$ref": "#/components/schemas/FunnelSeriesStep"
            },
            "type": "array"
          },
          "total_completed": {
            "minimum": 0,
            "type": "integer"
          },
          "total_entered": {
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "immature_users",
          "key",
          "other",
          "total_completed",
          "total_entered"
        ],
        "type": "object"
      },
      "FunnelSeriesStep": {
        "properties": {
          "conversion_rate": {
            "type": "number"
          },
          "drop_off_rate": {
            "type": "number"
          },
          "mature_users": {
            "minimum": 0,
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "users": {
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "mature_users",
          "name",
          "users"
        ],
        "type": "object"
      },
      "FunnelStep": {
        "properties": {
          "conversion_rate": {
            "type": "number"
          },
          "drop_off_rate": {
            "type": "number"
          },
          "mature_users": {
            "minimum": 0,
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "time_to_convert": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FunnelTimeToConvert"
              }
            ],
            "description": "Time from the previous step, over mature users who reached this step; null for the first step and when there is none."
          },
          "users": {
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "mature_users",
          "name",
          "users"
        ],
        "type": "object"
      },
      "FunnelStepSpec": {
        "properties": {
          "event": {
            "type": "string"
          },
          "filters": {
            "items": {
              "$ref": "#/components/schemas/Filter"
            },
            "type": "array"
          },
          "match": {
            "type": "string"
          },
          "window_seconds": {
            "type": "integer"
          }
        },
        "required": [
          "event"
        ],
        "type": "object"
      },
      "FunnelTimeToConvert": {
        "properties": {
          "average_seconds": {
            "type": "number"
          },
          "histogram": {
            "description": "Buckets [min_seconds, max_seconds) covering [0, window), empty ones included.",
            "items": {
              "$ref": "#/components/schemas/FunnelHistogramBucket"
            },
            "type": "array"
          },
          "median_seconds": {
            "description": "Exact: the value at position floor(0.5 * users) of the sorted whole-second durations (0-based).",
            "type": "integer"
          },
          "p90_seconds": {
            "description": "Exact: the value at position floor(0.9 * users) of the sorted whole-second durations (0-based).",
            "type": "integer"
          },
          "users": {
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "average_seconds",
          "median_seconds",
          "p90_seconds",
          "users"
        ],
        "type": "object"
      },
      "GetEventsProperties": {
        "properties": {
          "event_name": {
            "type": "string"
          },
          "properties": {
            "items": {
              "properties": {
                "key": {
                  "type": "string"
                },
                "value": {
                  "type": "string"
                }
              },
              "required": [
                "key",
                "value"
              ],
              "type": "object"
            },
            "type": "array"
          }
        },
        "required": [
          "event_name"
        ],
        "type": "object"
      },
      "GetProjectSnippetResponse": {
        "properties": {
          "install": {
            "type": "string"
          },
          "language": {
            "type": "string"
          },
          "note": {
            "type": "string"
          },
          "platform": {
            "type": "string"
          },
          "project_key": {
            "description": "Public ingest key; the write-only credential.",
            "type": "string"
          },
          "project_uuid": {
            "type": "string"
          },
          "snippet": {
            "description": "Copy-paste initialization code for the platform.",
            "type": "string"
          }
        },
        "required": [
          "language",
          "note",
          "platform",
          "project_key",
          "project_uuid",
          "snippet"
        ],
        "type": "object"
      },
      "ImportTarget": {
        "properties": {
          "allow_non_empty": {
            "type": "boolean"
          },
          "data_residency": {
            "type": "string"
          },
          "project_name": {
            "type": "string"
          },
          "project_uuid": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "allow_non_empty",
          "data_residency",
          "project_name"
        ],
        "type": "object"
      },
      "InsightsChange": {
        "properties": {
          "absolute": {
            "type": "number"
          },
          "relative": {
            "type": "number"
          }
        },
        "type": "object"
      },
      "InsightsCompare": {
        "properties": {
          "mode": {
            "type": "string"
          },
          "start": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "mode"
        ],
        "type": "object"
      },
      "InsightsComparePoint": {
        "properties": {
          "change": {
            "$ref": "#/components/schemas/InsightsChange"
          },
          "partial": {
            "type": "boolean"
          },
          "t": {
            "format": "date-time",
            "type": "string"
          },
          "v": {
            "type": "number"
          }
        },
        "required": [
          "change"
        ],
        "type": "object"
      },
      "InsightsCompareWindow": {
        "properties": {
          "end": {
            "format": "date-time",
            "type": "string"
          },
          "mode": {
            "type": "string"
          },
          "start": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "end",
          "mode",
          "start"
        ],
        "type": "object"
      },
      "InsightsDrilldownResult": {
        "properties": {
          "events": {
            "items": {
              "$ref": "#/components/schemas/Event"
            },
            "type": "array"
          },
          "has_more": {
            "type": "boolean"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "total_events": {
            "minimum": 0,
            "type": "integer"
          },
          "total_users": {
            "minimum": 0,
            "type": "integer"
          },
          "users": {
            "items": {
              "$ref": "#/components/schemas/InsightsDrilldownUser"
            },
            "type": "array"
          },
          "window": {
            "$ref": "#/components/schemas/InsightsWindow"
          }
        },
        "required": [
          "has_more",
          "limit",
          "offset",
          "total_events",
          "total_users",
          "window"
        ],
        "type": "object"
      },
      "InsightsDrilldownUser": {
        "properties": {
          "events": {
            "minimum": 0,
            "type": "integer"
          },
          "first_seen": {
            "format": "date-time",
            "type": "string"
          },
          "last_seen": {
            "format": "date-time",
            "type": "string"
          },
          "user_uuid": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "events",
          "first_seen",
          "last_seen",
          "user_uuid"
        ],
        "type": "object"
      },
      "InsightsFormula": {
        "properties": {
          "expression": {
            "description": "Query letters A-E, numbers (digits, optional decimals, optional leading minus), + - * / and parentheses. No functions, exponents or free SQL. Division by zero is null with reason division_by_zero.",
            "type": "string"
          },
          "label": {
            "type": "string"
          }
        },
        "required": [
          "expression",
          "label"
        ],
        "type": "object"
      },
      "InsightsFormulaPoint": {
        "properties": {
          "partial": {
            "type": "boolean"
          },
          "reason": {
            "type": "string"
          },
          "t": {
            "format": "date-time",
            "type": "string"
          },
          "v": {
            "type": "number"
          }
        },
        "required": [
          "t"
        ],
        "type": "object"
      },
      "InsightsFormulaQuery": {
        "properties": {
          "event": {
            "type": "string"
          },
          "filters": {
            "items": {
              "$ref": "#/components/schemas/Filter"
            },
            "type": "array"
          },
          "match": {
            "type": "string"
          },
          "metric": {
            "type": "string"
          },
          "property": {
            "type": "string"
          }
        },
        "required": [
          "event",
          "match",
          "metric",
          "property"
        ],
        "type": "object"
      },
      "InsightsFormulaResult": {
        "properties": {
          "formulas": {
            "items": {
              "$ref": "#/components/schemas/InsightsFormulaSeries"
            },
            "type": "array"
          },
          "interval": {
            "type": "string"
          },
          "queries": {
            "items": {
              "$ref": "#/components/schemas/InsightsSeries"
            },
            "type": "array"
          },
          "timezone": {
            "type": "string"
          }
        },
        "required": [
          "interval",
          "timezone"
        ],
        "type": "object"
      },
      "InsightsFormulaSeries": {
        "properties": {
          "expression": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "points": {
            "items": {
              "$ref": "#/components/schemas/InsightsFormulaPoint"
            },
            "type": "array"
          },
          "total": {
            "type": "number"
          },
          "total_reason": {
            "type": "string"
          },
          "unit": {
            "type": "string"
          }
        },
        "required": [
          "expression",
          "label",
          "unit"
        ],
        "type": "object"
      },
      "InsightsPoint": {
        "properties": {
          "numeric_values": {
            "minimum": 0,
            "type": "integer"
          },
          "partial": {
            "type": "boolean"
          },
          "t": {
            "format": "date-time",
            "type": "string"
          },
          "v": {
            "type": "number"
          }
        },
        "required": [
          "t"
        ],
        "type": "object"
      },
      "InsightsResult": {
        "properties": {
          "compare": {
            "$ref": "#/components/schemas/InsightsCompareWindow"
          },
          "interval": {
            "type": "string"
          },
          "series": {
            "items": {
              "$ref": "#/components/schemas/InsightsSeries"
            },
            "type": "array"
          },
          "timezone": {
            "type": "string"
          }
        },
        "required": [
          "interval",
          "timezone"
        ],
        "type": "object"
      },
      "InsightsSeries": {
        "properties": {
          "compare": {
            "$ref": "#/components/schemas/InsightsSeriesCompare"
          },
          "key": {
            "type": "string"
          },
          "non_numeric_values": {
            "minimum": 0,
            "type": "integer"
          },
          "numeric_values": {
            "minimum": 0,
            "type": "integer"
          },
          "other": {
            "type": "boolean"
          },
          "points": {
            "items": {
              "$ref": "#/components/schemas/InsightsPoint"
            },
            "type": "array"
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "key"
        ],
        "type": "object"
      },
      "InsightsSeriesCompare": {
        "properties": {
          "change": {
            "$ref": "#/components/schemas/InsightsChange"
          },
          "points": {
            "items": {
              "$ref": "#/components/schemas/InsightsComparePoint"
            },
            "type": "array"
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "change"
        ],
        "type": "object"
      },
      "InsightsWindow": {
        "properties": {
          "end": {
            "format": "date-time",
            "type": "string"
          },
          "start": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "end",
          "start"
        ],
        "type": "object"
      },
      "Organization": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/Status"
          },
          "status_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "uuid": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "name",
          "status_uuid",
          "updated_at"
        ],
        "type": "object"
      },
      "PageOfUser": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/User"
            },
            "type": "array"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "total": {
            "description": "Total matching users, for pagination.",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "limit",
          "offset",
          "total"
        ],
        "type": "object"
      },
      "Project": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "data_residency": {
            "description": "Region the project's events are stored in (US at launch).",
            "type": "string"
          },
          "events": {
            "items": {
              "$ref": "#/components/schemas/Event"
            },
            "type": "array"
          },
          "key": {
            "description": "Public ingest key. Safe to embed in apps; grants writes only.",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "organization": {
            "$ref": "#/components/schemas/Organization"
          },
          "organization_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "secret": {
            "description": "Plaintext project secret, present only in the response to creation or rotation. Store it; it is never shown again.",
            "type": "string"
          },
          "selected": {
            "type": "boolean"
          },
          "status": {
            "$ref": "#/components/schemas/Status"
          },
          "status_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "users": {
            "items": {
              "$ref": "#/components/schemas/User"
            },
            "type": "array"
          },
          "uuid": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "data_residency",
          "key",
          "name",
          "organization_uuid",
          "selected",
          "status_uuid",
          "updated_at"
        ],
        "type": "object"
      },
      "ProjectStorageUsage": {
        "properties": {
          "name": {
            "type": "string"
          },
          "percent": {
            "type": "number"
          },
          "project_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "reconciled_at": {
            "description": "When the total was last set from ClickHouse.",
            "format": "date-time",
            "type": "string"
          },
          "state": {
            "description": "ok, warning (at or past warning_percent), blocked (ingest answers 402 storage_budget_exceeded) or unknown (no total yet or the store could not be read; ingest is not limited meanwhile).",
            "type": "string"
          },
          "used_bytes": {
            "description": "Logical bytes stored by the project's retained events; null when state is unknown.",
            "type": "integer"
          }
        },
        "required": [
          "name",
          "project_uuid",
          "state"
        ],
        "type": "object"
      },
      "PurgeResult": {
        "properties": {
          "aggregates": {
            "type": "string"
          },
          "live_rows_remaining": {
            "additionalProperties": {
              "minimum": 0,
              "type": "integer"
            },
            "type": "object"
          },
          "physical_rows_remaining": {
            "additionalProperties": {
              "minimum": 0,
              "type": "integer"
            },
            "type": "object"
          }
        },
        "required": [
          "aggregates"
        ],
        "type": "object"
      },
      "PurposeConsent": {
        "properties": {
          "actor": {
            "type": "string"
          },
          "enforced": {
            "type": "boolean"
          },
          "purpose": {
            "type": "string"
          },
          "recorded_at": {
            "format": "date-time",
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "state": {
            "type": "string"
          }
        },
        "required": [
          "enforced",
          "purpose",
          "state"
        ],
        "type": "object"
      },
      "ReadinessReport": {
        "properties": {
          "components": {
            "additionalProperties": {
              "type": "string"
            },
            "type": "object"
          },
          "status": {
            "type": "string"
          }
        },
        "required": [
          "status"
        ],
        "type": "object"
      },
      "RequestPasswordReset": {
        "properties": {
          "email": {
            "type": "string"
          }
        },
        "required": [
          "email"
        ],
        "type": "object"
      },
      "RetentionBreakdown": {
        "properties": {
          "limit": {
            "type": "integer"
          },
          "property": {
            "type": "string"
          },
          "scope": {
            "type": "string"
          },
          "series": {
            "items": {
              "$ref": "#/components/schemas/RetentionSeries"
            },
            "type": "array"
          }
        },
        "required": [
          "limit",
          "property",
          "scope"
        ],
        "type": "object"
      },
      "RetentionCohort": {
        "properties": {
          "cells": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "cohort": {
            "format": "date-time",
            "type": "string"
          },
          "complete": {
            "type": "boolean"
          },
          "rates": {
            "items": {
              "type": "number"
            },
            "type": "array"
          },
          "retained": {
            "items": {
              "minimum": 0,
              "type": "integer"
            },
            "type": "array"
          },
          "size": {
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "cohort",
          "complete",
          "size"
        ],
        "type": "object"
      },
      "RetentionEvent": {
        "properties": {
          "event": {
            "type": "string"
          },
          "filters": {
            "items": {
              "$ref": "#/components/schemas/Filter"
            },
            "type": "array"
          },
          "match": {
            "type": "string"
          }
        },
        "required": [
          "event"
        ],
        "type": "object"
      },
      "RetentionResult": {
        "properties": {
          "breakdown": {
            "$ref": "#/components/schemas/RetentionBreakdown"
          },
          "cohorts": {
            "items": {
              "$ref": "#/components/schemas/RetentionCohort"
            },
            "type": "array"
          },
          "interval": {
            "type": "string"
          },
          "observed_until": {
            "format": "date-time",
            "type": "string"
          },
          "periods": {
            "type": "integer"
          }
        },
        "required": [
          "interval",
          "observed_until",
          "periods"
        ],
        "type": "object"
      },
      "RetentionSeries": {
        "properties": {
          "cohorts": {
            "items": {
              "$ref": "#/components/schemas/RetentionCohort"
            },
            "type": "array"
          },
          "key": {
            "type": "string"
          },
          "other": {
            "type": "boolean"
          }
        },
        "required": [
          "key",
          "other"
        ],
        "type": "object"
      },
      "Role": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "name": {
            "enum": [
              "owner",
              "admin",
              "viewer"
            ],
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "uuid": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "name",
          "updated_at",
          "uuid"
        ],
        "type": "object"
      },
      "SegmentBucket": {
        "properties": {
          "events": {
            "minimum": 0,
            "type": "integer"
          },
          "users": {
            "minimum": 0,
            "type": "integer"
          },
          "value": {
            "type": "string"
          }
        },
        "required": [
          "events",
          "users",
          "value"
        ],
        "type": "object"
      },
      "SegmentResult": {
        "properties": {
          "buckets": {
            "items": {
              "$ref": "#/components/schemas/SegmentBucket"
            },
            "type": "array"
          },
          "event_name": {
            "type": "string"
          },
          "property_key": {
            "type": "string"
          }
        },
        "required": [
          "event_name",
          "property_key"
        ],
        "type": "object"
      },
      "Status": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "name": {
            "enum": [
              "enabled",
              "disabled"
            ],
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "uuid": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "name",
          "updated_at",
          "uuid"
        ],
        "type": "object"
      },
      "StorageUsageReport": {
        "properties": {
          "budget_bytes": {
            "description": "Logical bytes each project may keep (decimal: 700000000 is 700 MB).",
            "type": "integer"
          },
          "limited": {
            "description": "False when the plan has no stored-bytes budget (paid plans, self-hosted installs); projects is then empty.",
            "type": "boolean"
          },
          "measure": {
            "description": "Always logical_row_bytes: the uncompressed size of the stored rows' values, not bytes on disk.",
            "type": "string"
          },
          "plan_code": {
            "type": "string"
          },
          "projects": {
            "items": {
              "$ref": "#/components/schemas/ProjectStorageUsage"
            },
            "type": "array"
          },
          "reconcile_interval_seconds": {
            "description": "How often each total is set again from ClickHouse; between two, it is ingest's running count.",
            "type": "integer"
          },
          "warning_percent": {
            "type": "integer"
          }
        },
        "required": [
          "budget_bytes",
          "limited",
          "measure",
          "plan_code",
          "reconcile_interval_seconds",
          "warning_percent"
        ],
        "type": "object"
      },
      "SubjectConsent": {
        "properties": {
          "history": {
            "items": {
              "$ref": "#/components/schemas/ConsentRecord"
            },
            "type": "array"
          },
          "history_truncated": {
            "type": "boolean"
          },
          "purge": {
            "$ref": "#/components/schemas/PurgeResult"
          },
          "purposes": {
            "items": {
              "$ref": "#/components/schemas/PurposeConsent"
            },
            "type": "array"
          },
          "suppressions": {
            "items": {
              "$ref": "#/components/schemas/Suppression"
            },
            "type": "array"
          },
          "user_id": {
            "type": "string"
          },
          "user_uuid": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "history_truncated",
          "user_uuid"
        ],
        "type": "object"
      },
      "SubjectExport": {
        "properties": {
          "events": {
            "items": {
              "$ref": "#/components/schemas/Event"
            },
            "type": "array"
          },
          "user": {
            "$ref": "#/components/schemas/User"
          }
        },
        "type": "object"
      },
      "Suppression": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "lifted_at": {
            "format": "date-time",
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "user_id": {
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "reason",
          "user_id"
        ],
        "type": "object"
      },
      "SystemUser": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "email_verified": {
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "organization": {
            "$ref": "#/components/schemas/Organization"
          },
          "organization_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "role": {
            "$ref": "#/components/schemas/Role"
          },
          "role_name": {
            "type": "string"
          },
          "role_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/Status"
          },
          "status_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "uuid": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "email",
          "email_verified",
          "name",
          "organization_uuid",
          "role_uuid",
          "status_uuid",
          "updated_at",
          "uuid"
        ],
        "type": "object"
      },
      "TimeSeriesData": {
        "properties": {
          "date": {
            "format": "date-time",
            "type": "string"
          },
          "events": {
            "minimum": 0,
            "type": "integer"
          },
          "users": {
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "date",
          "events",
          "users"
        ],
        "type": "object"
      },
      "Token": {
        "properties": {
          "expiration_date": {
            "format": "date-time",
            "type": "string"
          },
          "refresh_token": {
            "type": "string"
          },
          "token": {
            "type": "string"
          }
        },
        "required": [
          "expiration_date",
          "refresh_token",
          "token"
        ],
        "type": "object"
      },
      "TopEvents": {
        "properties": {
          "count": {
            "minimum": 0,
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "percentage": {
            "type": "number"
          }
        },
        "required": [
          "count",
          "name",
          "percentage"
        ],
        "type": "object"
      },
      "TrafficOverview": {
        "properties": {
          "avg_visit_duration_seconds": {
            "type": "number"
          },
          "bounce_rate": {
            "type": "number"
          },
          "total_pageviews": {
            "minimum": 0,
            "type": "integer"
          },
          "total_visits": {
            "minimum": 0,
            "type": "integer"
          },
          "unique_visitors": {
            "minimum": 0,
            "type": "integer"
          },
          "users": {
            "minimum": 0,
            "type": "integer"
          },
          "views_per_visit": {
            "type": "number"
          }
        },
        "required": [
          "avg_visit_duration_seconds",
          "bounce_rate",
          "total_pageviews",
          "total_visits",
          "unique_visitors",
          "users",
          "views_per_visit"
        ],
        "type": "object"
      },
      "TransferJob": {
        "properties": {
          "bundle_bytes": {
            "minimum": 0,
            "type": "integer"
          },
          "bundle_deleted": {
            "type": "boolean"
          },
          "bundle_sha256": {
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "created_by": {
            "format": "uuid",
            "type": "string"
          },
          "ended_at": {
            "format": "date-time",
            "type": "string"
          },
          "error": {
            "type": "string"
          },
          "expires_at": {
            "format": "date-time",
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "options": {
            "$ref": "#/components/schemas/TransferOptions"
          },
          "organization_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "progress": {
            "$ref": "#/components/schemas/TransferProgress"
          },
          "project_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "started_at": {
            "format": "date-time",
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "uuid": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "bundle_bytes",
          "bundle_deleted",
          "created_at",
          "created_by",
          "kind",
          "options",
          "organization_uuid",
          "progress",
          "project_uuid",
          "status",
          "updated_at",
          "uuid"
        ],
        "type": "object"
      },
      "TransferOptions": {
        "properties": {
          "from": {
            "format": "date-time",
            "type": "string"
          },
          "include_events": {
            "type": "boolean"
          },
          "source_export_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "to": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "include_events"
        ],
        "type": "object"
      },
      "TransferProgress": {
        "properties": {
          "boards": {
            "type": "integer"
          },
          "cohorts": {
            "type": "integer"
          },
          "config_stored": {
            "type": "boolean"
          },
          "event_part_rows": {
            "minimum": 0,
            "type": "integer"
          },
          "event_parts_done": {
            "type": "integer"
          },
          "events_done": {
            "minimum": 0,
            "type": "integer"
          },
          "events_suppressed": {
            "minimum": 0,
            "type": "integer"
          },
          "events_total": {
            "minimum": 0,
            "type": "integer"
          },
          "phase": {
            "type": "string"
          },
          "users_done": {
            "minimum": 0,
            "type": "integer"
          },
          "users_stored": {
            "type": "boolean"
          },
          "users_suppressed": {
            "minimum": 0,
            "type": "integer"
          },
          "users_total": {
            "minimum": 0,
            "type": "integer"
          },
          "warnings": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "boards",
          "cohorts",
          "event_part_rows",
          "event_parts_done",
          "events_done",
          "events_total",
          "users_done",
          "users_total"
        ],
        "type": "object"
      },
      "UpdatePassword": {
        "properties": {
          "new_password": {
            "type": "string"
          },
          "old_password": {
            "type": "string"
          }
        },
        "required": [
          "new_password",
          "old_password"
        ],
        "type": "object"
      },
      "User": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "custom_id": {
            "description": "Your identifier for the user, as sent in identify.",
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "events": {
            "items": {
              "$ref": "#/components/schemas/Event"
            },
            "type": "array"
          },
          "events_count": {
            "minimum": 0,
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "phone_number": {
            "type": "string"
          },
          "project": {
            "$ref": "#/components/schemas/Project"
          },
          "project_uuid": {
            "format": "uuid",
            "type": "string"
          },
          "properties": {
            "additionalProperties": {
              "type": "string"
            },
            "type": "object"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "uuid": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "custom_id",
          "email",
          "events_count",
          "name",
          "project_uuid",
          "updated_at"
        ],
        "type": "object"
      },
      "VerifyEmail": {
        "properties": {
          "token": {
            "type": "string"
          }
        },
        "required": [
          "token"
        ],
        "type": "object"
      },
      "Widget": {
        "properties": {
          "breakdown": {
            "$ref": "#/components/schemas/Breakdown"
          },
          "compare": {
            "type": "string"
          },
          "error": {
            "description": "Read only: why a stored report no longer validates. It is then not run.",
            "type": "string"
          },
          "formulas": {
            "description": "Formulas over the series (A to E in order), at most 5; not with a breakdown or a comparison. Grammar: docs/INSIGHTS_FORMULAS.md.",
            "items": {
              "$ref": "#/components/schemas/WidgetFormula"
            },
            "type": "array"
          },
          "id": {
            "type": "string"
          },
          "interval": {
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "metric": {
            "type": "string"
          },
          "property": {
            "type": "string"
          },
          "report": {
            "additionalProperties": true,
            "description": "A saved report's request: the body of its route without start and end (refused). Validated on save and on every read.",
            "type": "object"
          },
          "series": {
            "items": {
              "$ref": "#/components/schemas/WidgetSeries"
            },
            "type": "array"
          },
          "size": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "type": {
            "description": "\"\" for an Insights chart, or funnel, retention or flow for a saved report.",
            "type": "string"
          }
        },
        "required": [
          "id",
          "interval",
          "kind",
          "metric",
          "size",
          "title"
        ],
        "type": "object"
      },
      "WidgetFormula": {
        "properties": {
          "expression": {
            "type": "string"
          },
          "label": {
            "type": "string"
          }
        },
        "required": [
          "expression",
          "label"
        ],
        "type": "object"
      },
      "WidgetSeries": {
        "properties": {
          "event": {
            "type": "string"
          },
          "filters": {
            "items": {
              "$ref": "#/components/schemas/Filter"
            },
            "type": "array"
          },
          "label": {
            "type": "string"
          },
          "match": {
            "type": "string"
          }
        },
        "required": [
          "event",
          "label",
          "match"
        ],
        "type": "object"
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "bearerFormat": "JWT",
        "description": "Session token issued by the accounts service (or the legacy /v1/auth routes).",
        "scheme": "bearer",
        "type": "http"
      },
      "projectKey": {
        "description": "Public write key. Safe to embed in client applications; grants ingest only. Paired with X-Project-Secret it also grants read-only programmatic access.",
        "in": "header",
        "name": "X-Project-Key",
        "type": "apiKey"
      },
      "projectSecret": {
        "description": "Server-side project secret, paired with X-Project-Key for programmatic read access to one project. Shown once at project creation or secret rotation and stored hashed. Server-side only: apps and browsers send X-Project-Key alone, and a secret that ever shipped in a build must be rotated (POST /v1/projects/{project_uuid}/secret/rotate). See https://iforevents.com/docs/getting-started/authentication.",
        "in": "header",
        "name": "X-Project-Secret",
        "type": "apiKey"
      }
    }
  },
  "info": {
    "contact": {
      "name": "IForevents",
      "url": "https://iforevents.com/docs"
    },
    "description": "Self-hostable product analytics API.\n\nThree ways to authenticate, each for a different kind of caller:\n\n- **Ingest** (`/v1/events/*`): the public project key alone, in `X-Project-Key`. It is safe to embed in mobile and web clients because it grants writes only.\n- **Dashboard** (everything else): a session JWT in `Authorization`. Scoped to the caller's organization and role.\n- **Programmatic API** (`/v1/analytics/*`): a project key **and** its secret, in `X-Project-Key` and `X-Project-Secret`. Read-only, and pinned to that one project.\n\nProject credentials never satisfy organization-level routes (team, audit, project management) or any mutating route: a key and secret say nothing about who holds them.\n\nSessions are issued by the accounts service (`accounts.iforevents.com`) on IForevents Cloud and by the api itself on a self-hosted install; every route is scoped to the caller's organization.\n\nIngest attributes events to people through `X-User-Id`: your own user id, or an anonymous id the SDK generates and keeps per visitor. Any string up to 256 characters; the same value `identify` takes as `custom_id`.\n\nErrors share one shape: `{\"error\": \"<message>\"}` with the HTTP status carrying the kind (400 invalid input, 401 authentication, 403 permission, 404 not found or not yours, 409 conflict, 429 rate or quota limit).",
    "license": {
      "name": "IForevents Self-Hosted License 1.0",
      "url": "https://github.com/innovafour/iforevents-selfhosted/blob/main/LICENSE"
    },
    "title": "IForevents API",
    "version": "1.0.0"
  },
  "openapi": "3.1.0",
  "paths": {
    "/health": {
      "get": {
        "operationId": "getHealth",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                },
                "schema": {
                  "properties": {
                    "status": {
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Process is up"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [],
        "summary": "Liveness probe",
        "tags": [
          "health"
        ]
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenAPI",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "info": {
                    "title": "IForevents API",
                    "version": "1.0.0"
                  },
                  "openapi": "3.1.0"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "OpenAPI 3.1 document"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [],
        "summary": "This document",
        "tags": [
          "health"
        ]
      }
    },
    "/ready": {
      "get": {
        "description": "Pings ClickHouse, the one dependency the api cannot serve without; 503 with the error while it is down (Redis and RabbitMQ are optional: without them the api degrades, it does not stop).",
        "operationId": "getReadiness",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "components": {
                    "clickhouse": "ok"
                  },
                  "status": "ok"
                },
                "schema": {
                  "$ref": "#/components/schemas/ReadinessReport"
                }
              }
            },
            "description": "ClickHouse answers"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          },
          "503": {
            "content": {
              "application/json": {
                "example": {
                  "components": {
                    "clickhouse": "error: dial tcp: connection refused"
                  },
                  "status": "degraded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ReadinessReport"
                }
              }
            },
            "description": "A dependency is down"
          }
        },
        "security": [],
        "summary": "Readiness probe, checks dependencies",
        "tags": [
          "health"
        ]
      }
    },
    "/sdk/v1/iforevents.js": {
      "get": {
        "description": "Same as iforevents.min.js, unminified, for reading and debugging.",
        "operationId": "getBrowserSDKSource",
        "responses": {
          "200": {
            "content": {
              "application/javascript": {
                "example": "/* IForevents browser SDK v1 */ ...",
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "JavaScript"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [],
        "summary": "The browser SDK, readable build",
        "tags": [
          "health"
        ]
      }
    },
    "/sdk/v1/iforevents.min.js": {
      "get": {
        "description": "The single-file browser SDK (about 5 KB). Load it from your own api origin: `<script src=\"{api}/sdk/v1/iforevents.min.js\" async data-project-key=\"pk_...\" data-base-url=\"{api}\"></script>`. A self-hosted install serves it itself and never loads JavaScript from iforevents.com. Cached for an hour, revalidated by ETag.",
        "operationId": "getBrowserSDK",
        "responses": {
          "200": {
            "content": {
              "application/javascript": {
                "example": "/* IForevents browser SDK v1 */ ...",
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "JavaScript"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [],
        "summary": "The browser SDK, served by this api",
        "tags": [
          "health"
        ]
      }
    },
    "/v1/analytics/events": {
      "post": {
        "operationId": "queryEvents",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "end": "2026-09-13T12:30:45Z",
                "events": [
                  {
                    "event_name": "checkout_completed",
                    "properties": [
                      {
                        "key": "plan",
                        "value": "pro"
                      }
                    ]
                  }
                ],
                "limit": 100,
                "offset": 0,
                "start": "2026-08-14T00:00:00Z"
              },
              "schema": {
                "properties": {
                  "end": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "event_type": {
                    "enum": [
                      "track",
                      "identify",
                      "page_view"
                    ],
                    "type": "string"
                  },
                  "events": {
                    "description": "Optional filters: only events with these names, each with optional property key/value pairs.",
                    "items": {
                      "$ref": "#/components/schemas/GetEventsProperties"
                    },
                    "type": "array"
                  },
                  "filters": {
                    "items": {
                      "$ref": "#/components/schemas/Filter"
                    },
                    "type": "array"
                  },
                  "groups": {
                    "items": {
                      "$ref": "#/components/schemas/FilterGroup"
                    },
                    "type": "array"
                  },
                  "limit": {
                    "type": "integer"
                  },
                  "match": {
                    "type": "string"
                  },
                  "offset": {
                    "type": "integer"
                  },
                  "q": {
                    "type": "string"
                  },
                  "start": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "user": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "events": [
                    {
                      "created_at": "2026-09-13T12:30:45Z",
                      "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                      "parent_name": "checkout_completed",
                      "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                      "properties": {
                        "order_id": "ord_456",
                        "total": "99.99"
                      },
                      "type": "track",
                      "user_uuid": "00000000-0000-0000-8b20-15635fadf462",
                      "uuid": "00000000-0000-0000-3c9e-5b7a1d24f086"
                    }
                  ]
                },
                "schema": {
                  "properties": {
                    "events": {
                      "items": {
                        "$ref": "#/components/schemas/Event"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "events"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Matching events, newest first"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Query events with optional property filters",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/events/parents": {
      "get": {
        "operationId": "listEventNames",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "parents": [
                    {
                      "name": "checkout_completed",
                      "properties": [
                        "order_id",
                        "total"
                      ]
                    }
                  ]
                },
                "schema": {
                  "properties": {
                    "parents": {
                      "items": {
                        "$ref": "#/components/schemas/EventParentProperties"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "parents"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Names with properties"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Event names and the property keys seen on them",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/events/parents/{parent_name}/properties/{property_key}/values": {
      "get": {
        "operationId": "listEventPropertyValues",
        "parameters": [
          {
            "in": "path",
            "name": "parent_name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "property_key",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "values": [
                    {
                      "name": "checkout_completed",
                      "property": "plan",
                      "values": [
                        "free",
                        "pro"
                      ]
                    }
                  ]
                },
                "schema": {
                  "properties": {
                    "values": {
                      "items": {
                        "$ref": "#/components/schemas/EventParentPropertiesValues"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "values"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Distinct values"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Distinct values for one property",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/export/events": {
      "get": {
        "operationId": "exportEvents",
        "parameters": [
          {
            "$ref": "#/components/parameters/start"
          },
          {
            "$ref": "#/components/parameters/end"
          },
          {
            "$ref": "#/components/parameters/limit"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "text/csv": {
                "example": "uuid,user_uuid,event,type,created_at,properties\ne1f2…,6f1c…,checkout_completed,track,2026-09-13T12:30:45Z,currency=USD;order_id=ord_456\n",
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "CSV attachment, newest first, at most limit rows (default 1000, at most 10000). X-Export-Truncated says whether more rows matched; X-Export-Rows, X-Export-Row-Limit, X-Export-Start and X-Export-End describe the file. A cell starting with =, +, -, @, tab or CR is prefixed with an apostrophe so spreadsheets do not run it."
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Export events as CSV",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/export/users": {
      "get": {
        "operationId": "exportUsers",
        "parameters": [
          {
            "$ref": "#/components/parameters/start"
          },
          {
            "$ref": "#/components/parameters/end"
          },
          {
            "$ref": "#/components/parameters/limit"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "text/csv": {
                "example": "uuid,custom_id,name,email,phone_number,events_count,created_at\n6f1c…,user_12345,Ada Lovelace,ada@example.com,,42,2026-09-13T12:30:45Z\n",
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "CSV attachment, newest first, at most limit rows (default 1000, at most 10000). X-Export-Truncated says whether more rows matched; X-Export-Rows, X-Export-Row-Limit, X-Export-Start and X-Export-End describe the file. A cell starting with =, +, -, @, tab or CR is prefixed with an apostrophe so spreadsheets do not run it."
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Export tracked users as CSV",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/flows": {
      "post": {
        "operationId": "getFlow",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "direction": "after",
                "end": "2026-09-13T12:30:45Z",
                "event": "signup",
                "exclude": [
                  "heartbeat"
                ],
                "start": "2026-08-14T00:00:00Z",
                "steps": 4,
                "top_k": 5,
                "window_hours": 24
              },
              "schema": {
                "properties": {
                  "cohort_uuid": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "direction": {
                    "type": "string"
                  },
                  "end": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "event": {
                    "type": "string"
                  },
                  "exclude": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "min_users": {
                    "type": "integer"
                  },
                  "start": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "steps": {
                    "type": "integer"
                  },
                  "top_k": {
                    "type": "integer"
                  },
                  "window_hours": {
                    "type": "integer"
                  }
                },
                "required": [
                  "event"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "flow": {
                    "direction": "after",
                    "edges": [
                      {
                        "depth": 1,
                        "from": "signup",
                        "to": "project_created",
                        "to_other": false,
                        "users": 60
                      },
                      {
                        "depth": 1,
                        "from": "signup",
                        "to": "",
                        "to_other": true,
                        "users": 20
                      }
                    ],
                    "event": "signup",
                    "exclude": [],
                    "levels": [
                      {
                        "depth": 0,
                        "nodes": [
                          {
                            "dropoff": 20,
                            "name": "signup",
                            "other": false,
                            "users": 100
                          }
                        ]
                      },
                      {
                        "depth": 1,
                        "nodes": [
                          {
                            "dropoff": 10,
                            "name": "project_created",
                            "other": false,
                            "users": 60
                          },
                          {
                            "dropoff": 5,
                            "name": "",
                            "other": true,
                            "users": 20
                          }
                        ]
                      }
                    ],
                    "observed_until": "2026-09-13T12:30:45Z",
                    "open_window_users": 4,
                    "steps": 2,
                    "top_k": 5,
                    "users": 100,
                    "window_hours": 24
                  }
                },
                "schema": {
                  "properties": {
                    "flow": {
                      "$ref": "#/components/schemas/FlowResult"
                    }
                  },
                  "required": [
                    "flow"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "A bounded path graph. Per user, the anchor is the earliest event in [start, end); the path is the events strictly after it and before anchor + window (or strictly before it and after anchor - window, nearest first, for direction before), ordered by time then name, without excluded events, with consecutive repeats collapsed, cut at steps. Only events in [start, end) count. Each level names its top_k events by users and puts the rest in one Other node whose users are not followed further. dropoff counts users with no further event in their window."
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No event, or a value out of range: steps 1-6 (default 4), top_k 1-10 (default 5), window_hours 1-168 (default 24), at most ten excluded events, a range of at most 180 days"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "cohort_uuid is not a cohort of this project"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Paths after or before one event",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/funnel": {
      "post": {
        "operationId": "getFunnel",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "end": "2026-09-13T12:30:45Z",
                "start": "2026-08-14T00:00:00Z",
                "steps": [
                  "signup",
                  "project_created",
                  "first_event"
                ],
                "window_hours": 168
              },
              "schema": {
                "properties": {
                  "breakdown": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/Breakdown"
                      }
                    ],
                    "description": "Split by a property: event scope reads the user's entry (step 1) event, the smallest value on a same-second tie; user scope reads the current profile. A missing value is the key \"\"."
                  },
                  "breakdown_limit": {
                    "description": "Keys listed before the rest are summed into one Other series (key $other); 1 to 25, default 10. Keys rank by entrants, then key.",
                    "type": "integer"
                  },
                  "cohort_uuid": {
                    "description": "Count only the members of this saved cohort.",
                    "format": "uuid",
                    "type": "string"
                  },
                  "counting": {
                    "type": "string"
                  },
                  "end": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "exclusions": {
                    "description": "At most 5. A user who did a matching event strictly after their from_step and strictly before their to_step (or, if they never reached it, before their window ends) is removed from the whole funnel.",
                    "items": {
                      "$ref": "#/components/schemas/FunnelExclusion"
                    },
                    "type": "array"
                  },
                  "start": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "steps": {
                    "description": "2 to 10 ordered steps. Each is an event name or an object {event, filters, match}; a step matches only events of its name that pass its filters (event or user scope, at most 10). A user converts a step only after the previous one.",
                    "items": {
                      "$ref": "#/components/schemas/FunnelStepSpec"
                    },
                    "type": "array"
                  },
                  "window_hours": {
                    "description": "Conversion window; defaults to 168 (7 days).",
                    "type": "integer"
                  }
                },
                "required": [
                  "steps"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "funnel": {
                    "counting": "unique_users",
                    "immature_users": 100,
                    "observed_until": "2026-09-13T12:30:45Z",
                    "overall_conversion_rate": 64,
                    "steps": [
                      {
                        "conversion_rate": 100,
                        "drop_off_rate": null,
                        "mature_users": 900,
                        "name": "signup",
                        "users": 1000
                      },
                      {
                        "conversion_rate": 64,
                        "drop_off_rate": 36,
                        "mature_users": 576,
                        "name": "project_created",
                        "users": 640
                      }
                    ],
                    "total_completed": 640,
                    "total_entered": 1000,
                    "window_hours": 168
                  }
                },
                "schema": {
                  "properties": {
                    "funnel": {
                      "$ref": "#/components/schemas/FunnelResult"
                    }
                  },
                  "required": [
                    "funnel"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Users per step. Per user, the entry is the earliest first-step event in [start, end); each later step is the first matching event strictly after the previous one and before entry + window; only events in [start, end) count. A step with window_seconds must also happen less than that many seconds after the previous step (the earliest path is kept; a later path is not searched). Rates are over mature users (whose whole window ends by observed_until); the others are immature_users, never drop-offs. A rate is null when its denominator is zero. counting \"entries\" counts entry occurrences instead of users: every first-step event in [start, end) starts its own attempt, evaluated by the same rules, and every \"users\" count is then a count of entries."
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Fewer than two or more than ten steps, a step without an event, invalid step or exclusion filters, a window_seconds on the first step or outside 1 to the funnel window, an unsupported counting unit, more than five exclusions, from_step/to_step out of order, or an invalid breakdown"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "cohort_uuid is not a cohort of this project"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Ordered step conversion",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/funnel/drilldown": {
      "post": {
        "description": "Takes the funnel's own request plus step (1-based), status (converted: reached the step; dropped: reached it, window over, never reached the next step), key and other (the breakdown series, as the funnel names them), limit (1 to 100, default 50) and offset (at most 10000). Same project scope, rules, cohort and exclusions as the funnel; excluded units are never listed. total_users and total_units reconcile with the funnel: converted is the step's users, dropped the step's mature_users minus the next step's. Users are ordered by their earliest such entry, then user; step_times is that entry's path.",
        "operationId": "getFunnelDrilldown",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "end": "2026-09-13T12:30:45Z",
                "limit": 50,
                "start": "2026-08-14T00:00:00Z",
                "status": "dropped",
                "step": 1,
                "steps": [
                  "signup",
                  "project_created"
                ],
                "window_hours": 168
              },
              "schema": {
                "properties": {
                  "breakdown": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/Breakdown"
                      }
                    ],
                    "description": "Split by a property: event scope reads the user's entry (step 1) event, the smallest value on a same-second tie; user scope reads the current profile. A missing value is the key \"\"."
                  },
                  "breakdown_limit": {
                    "description": "Keys listed before the rest are summed into one Other series (key $other); 1 to 25, default 10. Keys rank by entrants, then key.",
                    "type": "integer"
                  },
                  "cohort_uuid": {
                    "description": "Count only the members of this saved cohort.",
                    "format": "uuid",
                    "type": "string"
                  },
                  "counting": {
                    "type": "string"
                  },
                  "end": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "exclusions": {
                    "description": "At most 5. A user who did a matching event strictly after their from_step and strictly before their to_step (or, if they never reached it, before their window ends) is removed from the whole funnel.",
                    "items": {
                      "$ref": "#/components/schemas/FunnelExclusion"
                    },
                    "type": "array"
                  },
                  "key": {
                    "type": "string"
                  },
                  "limit": {
                    "type": "integer"
                  },
                  "offset": {
                    "type": "integer"
                  },
                  "other": {
                    "type": "boolean"
                  },
                  "start": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "status": {
                    "type": "string"
                  },
                  "step": {
                    "type": "integer"
                  },
                  "steps": {
                    "description": "2 to 10 ordered steps. Each is an event name or an object {event, filters, match}; a step matches only events of its name that pass its filters (event or user scope, at most 10). A user converts a step only after the previous one.",
                    "items": {
                      "$ref": "#/components/schemas/FunnelStepSpec"
                    },
                    "type": "array"
                  },
                  "window_hours": {
                    "description": "Conversion window; defaults to 168 (7 days).",
                    "type": "integer"
                  }
                },
                "required": [
                  "steps",
                  "step",
                  "status"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "counting": "unique_users",
                  "has_more": true,
                  "limit": 50,
                  "offset": 0,
                  "status": "dropped",
                  "step": 1,
                  "total_units": 324,
                  "total_users": 324,
                  "users": [
                    {
                      "entry": "2026-08-14T09:12:00Z",
                      "step_times": [
                        "2026-08-14T09:12:00Z"
                      ],
                      "units": 1,
                      "user_uuid": "6f1c2d3e-0000-4000-8000-000000000001"
                    }
                  ]
                },
                "schema": {
                  "$ref": "#/components/schemas/FunnelDrillResult"
                }
              }
            },
            "description": "One page of users"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "As for the funnel, or a step out of range, a bad status (dropped on the last step), key/other without a breakdown, or a bad limit or offset"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "cohort_uuid is not a cohort of this project"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "The users behind one funnel step",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/init": {
      "post": {
        "description": "Metrics, top events, recent events, traffic overview, users and the daily series for one range. The body is optional.",
        "operationId": "getDashboardInit",
        "parameters": [
          {
            "description": "Project to query; defaults to the organization's selected project. Ignored for project-credential callers, who are pinned to their project.",
            "in": "header",
            "name": "X-Project-UUID",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "end": "2026-09-13T12:30:45Z",
                "limit": 50,
                "start": "2026-08-14T00:00:00Z"
              },
              "schema": {
                "properties": {
                  "end": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "event_type": {
                    "enum": [
                      "track",
                      "identify",
                      "page_view"
                    ],
                    "type": "string"
                  },
                  "events": {
                    "description": "Optional filters: only events with these names, each with optional property key/value pairs.",
                    "items": {
                      "$ref": "#/components/schemas/GetEventsProperties"
                    },
                    "type": "array"
                  },
                  "filters": {
                    "items": {
                      "$ref": "#/components/schemas/Filter"
                    },
                    "type": "array"
                  },
                  "groups": {
                    "items": {
                      "$ref": "#/components/schemas/FilterGroup"
                    },
                    "type": "array"
                  },
                  "limit": {
                    "type": "integer"
                  },
                  "match": {
                    "type": "string"
                  },
                  "offset": {
                    "type": "integer"
                  },
                  "q": {
                    "type": "string"
                  },
                  "start": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "user": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "events": [
                      {
                        "created_at": "2026-09-13T12:30:45Z",
                        "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                        "parent_name": "checkout_completed",
                        "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                        "properties": {
                          "order_id": "ord_456",
                          "total": "99.99"
                        },
                        "type": "track",
                        "user_uuid": "00000000-0000-0000-8b20-15635fadf462",
                        "uuid": "00000000-0000-0000-3c9e-5b7a1d24f086"
                      }
                    ],
                    "metrics": {
                      "avg_events_per_user": 40.2,
                      "events_today": 1930,
                      "total_events": 48210,
                      "total_users": 1200,
                      "unique_users_today": 87
                    },
                    "overview": {
                      "avg_visit_duration_seconds": 184.6,
                      "bounce_rate": 31.2,
                      "total_pageviews": 30110,
                      "total_visits": 4020,
                      "unique_visitors": 1180,
                      "users": 1200,
                      "views_per_visit": 7.5
                    },
                    "time_series": [
                      {
                        "date": "2026-09-12T00:00:00Z",
                        "events": 1802,
                        "users": 84
                      }
                    ],
                    "top_events": [
                      {
                        "count": 30110,
                        "name": "screen_view",
                        "percentage": 62.4
                      }
                    ],
                    "users": [
                      {
                        "created_at": "2026-09-13T12:30:45Z",
                        "custom_id": "user_12345",
                        "email": "ada@example.com",
                        "events_count": 42,
                        "name": "Ada Lovelace",
                        "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                        "properties": {
                          "plan": "pro"
                        },
                        "updated_at": "2026-09-13T12:30:45Z",
                        "uuid": "00000000-0000-0000-8b20-15635fadf462"
                      }
                    ]
                  }
                },
                "schema": {
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/DashboardInitResponse"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Dashboard payload"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Project not found in this organization"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Every dashboard panel in one call",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/init/stream": {
      "post": {
        "description": "text/event-stream; one `data:` frame with the same payload as /v1/analytics/init every `interval` seconds until the client disconnects.",
        "operationId": "streamDashboardInit",
        "parameters": [
          {
            "description": "Seconds between frames.",
            "in": "query",
            "name": "interval",
            "schema": {
              "default": 30,
              "maximum": 3600,
              "minimum": 5,
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "end": "2026-09-13T12:30:45Z",
                "start": "2026-08-14T00:00:00Z"
              },
              "schema": {
                "properties": {
                  "end": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "event_type": {
                    "enum": [
                      "track",
                      "identify",
                      "page_view"
                    ],
                    "type": "string"
                  },
                  "events": {
                    "description": "Optional filters: only events with these names, each with optional property key/value pairs.",
                    "items": {
                      "$ref": "#/components/schemas/GetEventsProperties"
                    },
                    "type": "array"
                  },
                  "filters": {
                    "items": {
                      "$ref": "#/components/schemas/Filter"
                    },
                    "type": "array"
                  },
                  "groups": {
                    "items": {
                      "$ref": "#/components/schemas/FilterGroup"
                    },
                    "type": "array"
                  },
                  "limit": {
                    "type": "integer"
                  },
                  "match": {
                    "type": "string"
                  },
                  "offset": {
                    "type": "integer"
                  },
                  "q": {
                    "type": "string"
                  },
                  "start": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "user": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "text/event-stream": {
                "example": "data: {\"data\":{\"metrics\":{\"total_users\":1200}}}\n\n",
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Event stream"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Server-sent events stream of the dashboard payload",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/insights": {
      "post": {
        "description": "Buckets created_at by hour, day, week (Monday-start) or month of the local calendar of timezone (an IANA name, default UTC; a day can last 23 or 25 hours); each point's t is its bucket start as a UTC instant. Points are filled for every bucket in the range (max 1000). Interval total skips the buckets: each series has its whole-window total and an empty points list, which suits rankings (breakdown_limit up to 1000). Metrics: total, unique_users (exact), per_user, and sum, avg, min or max of the event property named by property. A numeric metric reads a value only when the whole string parses as a finite number; anything else (missing, empty, text, nan, inf) is left out and counted in non_numeric_values. Values are IEEE doubles. A bucket with no numeric value has sum 0 and avg, min and max null (unknown, never 0). Without a breakdown there is one series keyed \"$all\"; with one, the top breakdown_limit values ranked by the metric (keys without a value last, ties by key), an absent property reported as key \"\", and the rest as one Other series (\"$other\", other: true).",
        "operationId": "getInsights",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "breakdown": {
                  "property": "plan",
                  "scope": "event"
                },
                "breakdown_limit": 10,
                "end": "2026-09-13T12:30:45Z",
                "filters": [
                  {
                    "operator": "eq",
                    "property": "plan",
                    "scope": "event",
                    "values": [
                      "pro",
                      "growth"
                    ]
                  }
                ],
                "interval": "day",
                "match": "all",
                "metric": "total",
                "start": "2026-09-01T00:00:00Z"
              },
              "schema": {
                "properties": {
                  "breakdown": {
                    "$ref": "#/components/schemas/Breakdown"
                  },
                  "breakdown_limit": {
                    "description": "Values listed before the rest are summed into one Other series (key $other); 1 to 25, default 10. With interval total, 1 to 1000.",
                    "type": "integer"
                  },
                  "compare": {
                    "$ref": "#/components/schemas/InsightsCompare"
                  },
                  "end": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "event": {
                    "type": "string"
                  },
                  "filters": {
                    "items": {
                      "$ref": "#/components/schemas/Filter"
                    },
                    "type": "array"
                  },
                  "groups": {
                    "items": {
                      "$ref": "#/components/schemas/FilterGroup"
                    },
                    "type": "array"
                  },
                  "interval": {
                    "description": "hour, day (default), week (Monday-start) or month buckets of the local calendar of timezone; total has no buckets: every series carries only its whole-window total and points is empty.",
                    "type": "string"
                  },
                  "match": {
                    "type": "string"
                  },
                  "metric": {
                    "type": "string"
                  },
                  "property": {
                    "type": "string"
                  },
                  "start": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "timezone": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "interval": "day",
                  "series": [
                    {
                      "key": "$all",
                      "points": [
                        {
                          "t": "2026-09-01T00:00:00Z",
                          "v": 12
                        }
                      ],
                      "total": 1234
                    }
                  ],
                  "timezone": "UTC"
                },
                "schema": {
                  "$ref": "#/components/schemas/InsightsResult"
                }
              }
            },
            "description": "One series per key. With compare, every series also carries compare: the same query over the earlier window (moved back by the window's own bucket count for previous_period, a year for previous_year, or to the bucket holding compare.start for custom), with compare.points[i] the bucket compared with points[i] (its own t; null when the earlier window has fewer buckets) and change = current - previous (relative is null when the previous value is 0 or unknown). A breakdown compares the same top values; Other holds every other value of the earlier window."
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Invalid filter, interval, metric, timezone or compare, a numeric metric without property (or property with a count metric), breakdown_limit out of range (1 to 25, or 1 to 1000 with interval total), or more than 1000 buckets"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "A bucketed metric over a window, optionally broken down by a property",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/insights/drilldown": {
      "post": {
        "description": "Takes the chart's own insights request plus point (the t of one of its points; omitted for the whole window), key and other (the breakdown series), show (events or users), limit (1 to 100, default 50) and offset (at most 10000). Reads the point's bucket clipped to [start, end), under the same project and filters. total_events and total_users are the point's event count and unique users. Events are newest first; users by event count, then user. Other is every value outside the chart window's top values.",
        "operationId": "getInsightsDrilldown",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "breakdown": {
                  "property": "plan",
                  "scope": "event"
                },
                "end": "2026-09-13T12:30:45Z",
                "interval": "day",
                "key": "pro",
                "limit": 50,
                "metric": "total",
                "point": "2026-09-02T05:00:00Z",
                "show": "users",
                "start": "2026-09-01T00:00:00Z",
                "timezone": "America/Bogota"
              },
              "schema": {
                "properties": {
                  "breakdown": {
                    "$ref": "#/components/schemas/Breakdown"
                  },
                  "breakdown_limit": {
                    "description": "Values listed before the rest are summed into one Other series (key $other); 1 to 25, default 10. With interval total, 1 to 1000.",
                    "type": "integer"
                  },
                  "compare": {
                    "$ref": "#/components/schemas/InsightsCompare"
                  },
                  "end": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "event": {
                    "type": "string"
                  },
                  "filters": {
                    "items": {
                      "$ref": "#/components/schemas/Filter"
                    },
                    "type": "array"
                  },
                  "groups": {
                    "items": {
                      "$ref": "#/components/schemas/FilterGroup"
                    },
                    "type": "array"
                  },
                  "interval": {
                    "description": "hour, day (default), week (Monday-start) or month buckets of the local calendar of timezone; total has no buckets: every series carries only its whole-window total and points is empty.",
                    "type": "string"
                  },
                  "key": {
                    "type": "string"
                  },
                  "limit": {
                    "type": "integer"
                  },
                  "match": {
                    "type": "string"
                  },
                  "metric": {
                    "type": "string"
                  },
                  "offset": {
                    "type": "integer"
                  },
                  "other": {
                    "type": "boolean"
                  },
                  "point": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "property": {
                    "type": "string"
                  },
                  "show": {
                    "type": "string"
                  },
                  "start": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "timezone": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "has_more": false,
                  "limit": 50,
                  "offset": 0,
                  "total_events": 42,
                  "total_users": 7,
                  "users": [
                    {
                      "events": 12,
                      "first_seen": "2026-09-02T06:10:00Z",
                      "last_seen": "2026-09-02T22:41:00Z",
                      "user_uuid": "6f1c2d3e-0000-4000-8000-000000000001"
                    }
                  ],
                  "window": {
                    "end": "2026-09-03T05:00:00Z",
                    "start": "2026-09-02T05:00:00Z"
                  }
                },
                "schema": {
                  "$ref": "#/components/schemas/InsightsDrilldownResult"
                }
              }
            },
            "description": "One page of the point's events or users"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "As for insights, or a point that is not a bucket start of the window, or a bad show, limit or offset"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "The events or users behind one insights point",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/insights/formulas": {
      "post": {
        "operationId": "getInsightsFormulas",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "end": "2026-09-13T12:30:45Z",
                "formulas": [
                  {
                    "expression": "A / B",
                    "label": "Purchases per buyer"
                  }
                ],
                "interval": "day",
                "queries": [
                  {
                    "event": "purchase",
                    "metric": "total"
                  },
                  {
                    "event": "purchase",
                    "metric": "unique_users"
                  }
                ],
                "start": "2026-09-01T00:00:00Z",
                "timezone": "UTC"
              },
              "schema": {
                "properties": {
                  "end": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "formulas": {
                    "items": {
                      "$ref": "#/components/schemas/InsightsFormula"
                    },
                    "type": "array"
                  },
                  "groups": {
                    "items": {
                      "$ref": "#/components/schemas/FilterGroup"
                    },
                    "type": "array"
                  },
                  "interval": {
                    "type": "string"
                  },
                  "queries": {
                    "items": {
                      "$ref": "#/components/schemas/InsightsFormulaQuery"
                    },
                    "type": "array"
                  },
                  "start": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "timezone": {
                    "type": "string"
                  }
                },
                "required": [
                  "queries",
                  "formulas"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "formulas": [
                    {
                      "expression": "(A / B)",
                      "label": "Purchases per buyer",
                      "points": [
                        {
                          "reason": "division_by_zero",
                          "t": "2026-09-01T00:00:00Z",
                          "v": null
                        }
                      ],
                      "total": null,
                      "total_reason": "division_by_zero",
                      "unit": "(events/users)"
                    }
                  ],
                  "interval": "day",
                  "queries": [
                    {
                      "key": "A",
                      "points": [
                        {
                          "t": "2026-09-01T00:00:00Z",
                          "v": 12
                        }
                      ],
                      "total": 12
                    },
                    {
                      "key": "B",
                      "points": [
                        {
                          "t": "2026-09-01T00:00:00Z",
                          "v": 0
                        }
                      ],
                      "total": 0
                    }
                  ],
                  "timezone": "UTC"
                },
                "schema": {
                  "$ref": "#/components/schemas/InsightsFormulaResult"
                }
              }
            },
            "description": "Each query's series (keys A to E) and each formula bucket by bucket, in binary64, every operation applied once as written. A null value carries reason unknown_value, division_by_zero or numeric_overflow (the left operand's first). total is the formula over the queries' whole-window totals."
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "1 to 5 queries and formulas are required; a grammar error (with its position), unlike units added or subtracted, or an invalid query"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Formulas over named Insights queries",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/metrics": {
      "get": {
        "operationId": "getMetrics",
        "parameters": [
          {
            "$ref": "#/components/parameters/start"
          },
          {
            "$ref": "#/components/parameters/end"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "metrics": {
                    "avg_events_per_user": 40.2,
                    "events_today": 1930,
                    "total_events": 48210,
                    "total_users": 1200,
                    "unique_users_today": 87
                  }
                },
                "schema": {
                  "properties": {
                    "metrics": {
                      "$ref": "#/components/schemas/AnalyticsMetrics"
                    }
                  },
                  "required": [
                    "metrics"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Counters for the range"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Headline counters",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/overview": {
      "get": {
        "operationId": "getTrafficOverview",
        "parameters": [
          {
            "$ref": "#/components/parameters/start"
          },
          {
            "$ref": "#/components/parameters/end"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "overview": {
                    "avg_visit_duration_seconds": 184.6,
                    "bounce_rate": 31.2,
                    "total_pageviews": 30110,
                    "total_visits": 4020,
                    "unique_visitors": 1180,
                    "users": 1200,
                    "views_per_visit": 7.5
                  }
                },
                "schema": {
                  "properties": {
                    "overview": {
                      "$ref": "#/components/schemas/TrafficOverview"
                    }
                  },
                  "required": [
                    "overview"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Visits, pageviews, bounce rate"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Traffic KPIs",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/projects": {
      "get": {
        "operationId": "listProjects",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "projects": [
                    {
                      "created_at": "2026-09-13T12:30:45Z",
                      "data_residency": "US",
                      "key": "3142566d8c88721d6d34bd9443d556bf",
                      "name": "Mobile app",
                      "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                      "selected": true,
                      "status_uuid": "9d3f1e2c-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                      "updated_at": "2026-09-13T12:30:45Z",
                      "uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f"
                    }
                  ]
                },
                "schema": {
                  "properties": {
                    "projects": {
                      "items": {
                        "$ref": "#/components/schemas/Project"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "projects"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Enabled projects"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Projects owned by the caller's organization",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/projects/{project_uuid}": {
      "delete": {
        "description": "Ingest with the project's key stops; stored events stay until the retention window ends.",
        "operationId": "deleteProject",
        "parameters": [
          {
            "$ref": "#/components/parameters/projectUUID"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                },
                "schema": {
                  "properties": {
                    "status": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Disabled"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Project not found in this organization"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Disable a project (admin only)",
        "tags": [
          "projects"
        ]
      }
    },
    "/v1/analytics/projects/{project_uuid}/select": {
      "post": {
        "operationId": "selectProject",
        "parameters": [
          {
            "$ref": "#/components/parameters/projectUUID"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                },
                "schema": {
                  "properties": {
                    "status": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Selected"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Project not found in this organization"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Mark a project as the organization's active one (admin only)",
        "tags": [
          "projects"
        ]
      }
    },
    "/v1/analytics/properties": {
      "get": {
        "description": "Sorted, max 500, custom keys only: the $-prefixed built-ins (\\$event, \\$type, \\$email, ...) are not listed here, the client already knows them. truncated is true when more keys exist than were returned.",
        "operationId": "listProperties",
        "parameters": [
          {
            "in": "query",
            "name": "scope",
            "required": true,
            "schema": {
              "enum": [
                "event",
                "user"
              ],
              "type": "string"
            }
          },
          {
            "description": "For scope=event, only keys seen on this event name.",
            "in": "query",
            "name": "event",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "properties": [
                    "country",
                    "plan"
                  ],
                  "truncated": false
                },
                "schema": {
                  "properties": {
                    "properties": {
                      "items": {
                        "type": "string"
                      },
                      "type": "array"
                    },
                    "truncated": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "properties",
                    "truncated"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Property keys"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Custom property keys for the explorer filter and breakdown pickers",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/properties/values": {
      "get": {
        "description": "Max 100, ties broken by value. truncated is true when more values exist than were returned. Supports the $event, $type, $email, $custom_id and $name built-ins in addition to custom keys. Event values are counted over events in [start, end), by default the last 30 days and at most 90; the answer echoes the window. User values are counted over current profiles.",
        "operationId": "listPropertyValues",
        "parameters": [
          {
            "in": "query",
            "name": "scope",
            "required": true,
            "schema": {
              "enum": [
                "event",
                "user"
              ],
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "property",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "For scope=event, only values seen on this event name.",
            "in": "query",
            "name": "event",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Case-insensitive substring filter.",
            "in": "query",
            "name": "q",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "For scope=event, the window start (RFC3339). Default: end minus 30 days.",
            "in": "query",
            "name": "start",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "description": "For scope=event, the window end, exclusive (RFC3339). Default: now.",
            "in": "query",
            "name": "end",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "end": "2026-09-13T12:30:45Z",
                  "start": "2026-09-03T12:00:00Z",
                  "truncated": false,
                  "values": [
                    "pro",
                    "growth"
                  ]
                },
                "schema": {
                  "properties": {
                    "end": {
                      "description": "Window end, exclusive (scope=event only).",
                      "format": "date-time",
                      "type": "string"
                    },
                    "start": {
                      "description": "Window read (scope=event only).",
                      "format": "date-time",
                      "type": "string"
                    },
                    "truncated": {
                      "type": "boolean"
                    },
                    "values": {
                      "items": {
                        "type": "string"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "values",
                    "truncated"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Values, most frequent first"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Bad scope or property, or a window that is reversed or longer than 90 days"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Distinct values of one property, most frequent first",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/retention": {
      "post": {
        "operationId": "getRetention",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "end": "2026-09-13T12:30:45Z",
                "periods": 8,
                "start": "2026-07-01T00:00:00Z"
              },
              "schema": {
                "properties": {
                  "breakdown": {
                    "$ref": "#/components/schemas/Breakdown"
                  },
                  "breakdown_limit": {
                    "type": "integer"
                  },
                  "cohort_uuid": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "end": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "entry_event": {
                    "$ref": "#/components/schemas/RetentionEvent"
                  },
                  "interval": {
                    "type": "string"
                  },
                  "periods": {
                    "description": "Number of weekly periods to report; defaults to 8.",
                    "type": "integer"
                  },
                  "return_event": {
                    "$ref": "#/components/schemas/RetentionEvent"
                  },
                  "start": {
                    "format": "date-time",
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "retention": {
                    "cohorts": [
                      {
                        "cells": [
                          "complete",
                          "complete",
                          "partial",
                          "future"
                        ],
                        "cohort": "2026-07-06T00:00:00Z",
                        "complete": true,
                        "rates": [
                          100,
                          66.7,
                          50.8,
                          null
                        ],
                        "retained": [
                          120,
                          80,
                          61,
                          null
                        ],
                        "size": 120
                      }
                    ],
                    "interval": "week",
                    "observed_until": "2026-09-13T12:30:45Z",
                    "periods": 3
                  }
                },
                "schema": {
                  "properties": {
                    "retention": {
                      "$ref": "#/components/schemas/RetentionResult"
                    }
                  },
                  "required": [
                    "retention"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Weekly cohorts (Monday weeks) of users whose first active day ever is in the range. cells[p] is complete, partial (the week runs past observed_until: a count so far) or future (not observed: retained and rates are null, never zero)."
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "An unknown interval, periods out of range for a day or month interval (or for any request with entry, return or breakdown), more than 366 cohort buckets, an invalid entry or return event, or a breakdown that is not event scope or lacks entry_event"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "cohort_uuid is not a cohort of this project"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Cohort retention: daily, weekly or monthly, with optional entry and return events and an entry-event breakdown",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/segments": {
      "post": {
        "operationId": "getSegments",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "end": "2026-09-13T12:30:45Z",
                "event_name": "checkout_completed",
                "limit": 20,
                "property_key": "plan",
                "start": "2026-08-14T00:00:00Z"
              },
              "schema": {
                "properties": {
                  "end": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "event_name": {
                    "type": "string"
                  },
                  "limit": {
                    "type": "integer"
                  },
                  "property_key": {
                    "type": "string"
                  },
                  "start": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "values": {
                    "description": "Optional subset of property values to report.",
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  }
                },
                "required": [
                  "event_name",
                  "property_key"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "segments": {
                    "buckets": [
                      {
                        "events": 402,
                        "users": 310,
                        "value": "pro"
                      },
                      {
                        "events": 131,
                        "users": 120,
                        "value": "free"
                      }
                    ],
                    "event_name": "checkout_completed",
                    "property_key": "plan"
                  }
                },
                "schema": {
                  "properties": {
                    "segments": {
                      "$ref": "#/components/schemas/SegmentResult"
                    }
                  },
                  "required": [
                    "segments"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Buckets per value"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Break one event down by a property value",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/timeseries": {
      "get": {
        "operationId": "getTimeSeries",
        "parameters": [
          {
            "$ref": "#/components/parameters/start"
          },
          {
            "$ref": "#/components/parameters/end"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "time_series": [
                    {
                      "date": "2026-09-12T00:00:00Z",
                      "events": 1802,
                      "users": 84
                    }
                  ]
                },
                "schema": {
                  "properties": {
                    "time_series": {
                      "items": {
                        "$ref": "#/components/schemas/TimeSeriesData"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "time_series"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "One point per day"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Users and events per day",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/top-events": {
      "get": {
        "operationId": "getTopEvents",
        "parameters": [
          {
            "$ref": "#/components/parameters/start"
          },
          {
            "$ref": "#/components/parameters/end"
          },
          {
            "$ref": "#/components/parameters/limit"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "top_events": [
                    {
                      "count": 30110,
                      "name": "screen_view",
                      "percentage": 62.4
                    }
                  ]
                },
                "schema": {
                  "properties": {
                    "top_events": {
                      "items": {
                        "$ref": "#/components/schemas/TopEvents"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "top_events"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Events by count"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Most frequent events",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/users": {
      "get": {
        "operationId": "listUsers",
        "parameters": [
          {
            "$ref": "#/components/parameters/start"
          },
          {
            "$ref": "#/components/parameters/end"
          },
          {
            "description": "Case-insensitive match on name, email or custom_id, or an exact uuid",
            "in": "query",
            "name": "q",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/offset"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "page": {
                    "items": [
                      {
                        "created_at": "2026-09-13T12:30:45Z",
                        "custom_id": "user_12345",
                        "email": "ada@example.com",
                        "events_count": 42,
                        "name": "Ada Lovelace",
                        "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                        "properties": {
                          "plan": "pro"
                        },
                        "updated_at": "2026-09-13T12:30:45Z",
                        "uuid": "00000000-0000-0000-8b20-15635fadf462"
                      }
                    ],
                    "limit": 100,
                    "offset": 0,
                    "total": 1
                  },
                  "users": [
                    {
                      "created_at": "2026-09-13T12:30:45Z",
                      "custom_id": "user_12345",
                      "email": "ada@example.com",
                      "events_count": 42,
                      "name": "Ada Lovelace",
                      "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                      "properties": {
                        "plan": "pro"
                      },
                      "updated_at": "2026-09-13T12:30:45Z",
                      "uuid": "00000000-0000-0000-8b20-15635fadf462"
                    }
                  ]
                },
                "schema": {
                  "properties": {
                    "page": {
                      "$ref": "#/components/schemas/PageOfUser"
                    },
                    "users": {
                      "items": {
                        "$ref": "#/components/schemas/User"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "users",
                    "page"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Page of users"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Paginated tracked users",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/audit": {
      "get": {
        "description": "Newest first. Filter by action, actor and time range; page with limit and offset. total counts every row the filter matches.",
        "operationId": "listAuditEntries",
        "parameters": [
          {
            "description": "Exact action name, e.g. project.created",
            "in": "query",
            "name": "action",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Only entries by this user",
            "in": "query",
            "name": "actor_uuid",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/start"
          },
          {
            "$ref": "#/components/parameters/end"
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "$ref": "#/components/parameters/offset"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "entries": [
                    {
                      "action": "project.created",
                      "actor_uuid": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                      "created_at": "2026-09-13T12:30:45Z",
                      "ip_address": "203.0.113.7",
                      "metadata": {},
                      "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                      "target_type": "project",
                      "target_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f"
                    }
                  ],
                  "limit": 100,
                  "offset": 0,
                  "total": 1
                },
                "schema": {
                  "properties": {
                    "entries": {
                      "items": {
                        "$ref": "#/components/schemas/AuditEntry"
                      },
                      "type": "array"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    },
                    "total": {
                      "format": "int64",
                      "type": "integer"
                    }
                  },
                  "required": [
                    "entries",
                    "total",
                    "limit",
                    "offset"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Page of the trail"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Caller is not an admin"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Audit log for the caller's organization (admin only)",
        "tags": [
          "team"
        ]
      }
    },
    "/v1/audit/export": {
      "get": {
        "description": "Same filters as the listing; up to 100,000 rows, newest first. Metadata is a JSON object per row.",
        "operationId": "exportAuditEntries",
        "parameters": [
          {
            "description": "Exact action name",
            "in": "query",
            "name": "action",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Only entries by this user",
            "in": "query",
            "name": "actor_uuid",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/start"
          },
          {
            "$ref": "#/components/parameters/end"
          },
          {
            "description": "Only csv is supported",
            "in": "query",
            "name": "format",
            "schema": {
              "enum": [
                "csv"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "text/csv": {
                "example": "timestamp,actor_uuid,action,target_type,target_uuid,ip_address,metadata\n2026-09-13T12:30:45Z,6f1c…,project.created,project,9c0f…,203.0.113.7,\"{}\"\n",
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "CSV attachment"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Caller is not an admin"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Audit log as CSV (admin only)",
        "tags": [
          "team"
        ]
      }
    },
    "/v1/auth/email/verify": {
      "post": {
        "operationId": "verifyEmail",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "token": "evt_5d2a…"
              },
              "schema": {
                "$ref": "#/components/schemas/VerifyEmail"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": "email verified"
                },
                "schema": {
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "message"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Verified"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Token expired or already used"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [],
        "summary": "Confirm an email address",
        "tags": [
          "auth"
        ]
      }
    },
    "/v1/auth/email/verify/resend": {
      "post": {
        "operationId": "resendEmailVerification",
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "message": "verification email sent"
                },
                "schema": {
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "message"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Sent"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No session"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Send a fresh verification link",
        "tags": [
          "auth"
        ]
      }
    },
    "/v1/auth/login": {
      "post": {
        "operationId": "login",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "email": "ada@example.com",
                "password": "correct horse battery staple"
              },
              "schema": {
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string"
                  }
                },
                "required": [
                  "email",
                  "password"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "token": {
                    "expiration_date": "2026-09-13T13:30:45Z",
                    "refresh_token": "rt_2f7c…",
                    "token": "eyJhbGciOiJFZERTQSJ9.e30.sig"
                  },
                  "user": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "email": "ada@example.com",
                    "email_verified": true,
                    "name": "Ada Lovelace",
                    "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                    "role_name": "admin",
                    "role_uuid": "7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
                    "status_uuid": "9d3f1e2c-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f"
                  }
                },
                "schema": {
                  "properties": {
                    "token": {
                      "$ref": "#/components/schemas/Token"
                    },
                    "user": {
                      "$ref": "#/components/schemas/SystemUser"
                    }
                  },
                  "required": [
                    "user",
                    "token"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Signed in"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Wrong email or password"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Account disabled"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [],
        "summary": "Exchange credentials for a token pair",
        "tags": [
          "auth"
        ]
      }
    },
    "/v1/auth/logout": {
      "post": {
        "description": "Signs the account out on every device: every one of its refresh tokens is revoked. Access tokens already issued stay valid until they expire (`ACCESS_TOKEN_TTL_MINUTES`).",
        "operationId": "logout",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": "logged out"
                },
                "schema": {
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "message"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Logged out"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No session"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Revoke every refresh token for the caller",
        "tags": [
          "auth"
        ]
      }
    },
    "/v1/auth/me": {
      "get": {
        "operationId": "getMe",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "user": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "email": "ada@example.com",
                    "email_verified": true,
                    "name": "Ada Lovelace",
                    "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                    "role_name": "admin",
                    "role_uuid": "7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
                    "status_uuid": "9d3f1e2c-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f"
                  }
                },
                "schema": {
                  "properties": {
                    "user": {
                      "$ref": "#/components/schemas/SystemUser"
                    }
                  },
                  "required": [
                    "user"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Caller"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No session"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "The authenticated account",
        "tags": [
          "auth"
        ]
      }
    },
    "/v1/auth/me/password": {
      "patch": {
        "description": "Revokes every refresh token of the account, the caller's included: each session, this one too, ends when its access token expires.",
        "operationId": "updatePassword",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "new_password": "a longer passphrase 2026",
                "old_password": "correct horse battery staple"
              },
              "schema": {
                "$ref": "#/components/schemas/UpdatePassword"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": "password updated successfully"
                },
                "schema": {
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "message"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Password changed"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Old password wrong"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Change the password and revoke every session",
        "tags": [
          "auth"
        ]
      }
    },
    "/v1/auth/organization/user/register": {
      "post": {
        "operationId": "inviteTeamMember",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "email": "grace@example.com",
                "full_name": "Grace Hopper",
                "password": "a temporary passphrase",
                "role_name": "viewer"
              },
              "schema": {
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "full_name": {
                    "type": "string"
                  },
                  "organization_name": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string"
                  },
                  "role_name": {
                    "description": "Ignored on public registration: the first user of an organization is its owner.",
                    "type": "string"
                  }
                },
                "required": [
                  "full_name",
                  "email",
                  "password",
                  "role_name"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "user": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "email": "ada@example.com",
                    "email_verified": true,
                    "name": "Ada Lovelace",
                    "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                    "role_name": "viewer",
                    "role_uuid": "7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
                    "status_uuid": "9d3f1e2c-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f"
                  }
                },
                "schema": {
                  "properties": {
                    "user": {
                      "$ref": "#/components/schemas/SystemUser"
                    }
                  },
                  "required": [
                    "user"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Member created"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Caller is not an admin"
          },
          "409": {
            "content": {
              "application/json": {
                "example": {
                  "error": "already exists"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Email already registered"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Invite a user into the caller's organization (admin only)",
        "tags": [
          "team"
        ]
      }
    },
    "/v1/auth/password/reset/confirm": {
      "post": {
        "operationId": "confirmPasswordReset",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "new_password": "a longer passphrase 2026",
                "token": "prt_8c1e…"
              },
              "schema": {
                "$ref": "#/components/schemas/ConfirmPasswordReset"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": "password updated"
                },
                "schema": {
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "message"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Password changed"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Token expired or already used"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [],
        "summary": "Consume a reset token and set a new password",
        "tags": [
          "auth"
        ]
      }
    },
    "/v1/auth/password/reset/request": {
      "post": {
        "description": "Always answers 202 so the route cannot be used to probe which emails exist.",
        "operationId": "requestPasswordReset",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "email": "ada@example.com"
              },
              "schema": {
                "$ref": "#/components/schemas/RequestPasswordReset"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "message": "if the account exists, a reset link has been sent"
                },
                "schema": {
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "message"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Accepted"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [],
        "summary": "Send a reset link",
        "tags": [
          "auth"
        ]
      }
    },
    "/v1/auth/refresh": {
      "post": {
        "description": "Returns a new pair and revokes the presented refresh token, which is single use. Every sign-in has its own refresh token, so a rotation leaves the account's other sessions signed in, and a rejected token revokes nothing. The new refresh token lasts `REFRESH_TOKEN_TTL_HOURS` from now.",
        "operationId": "refreshToken",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "refresh_token": "rt_2f7c…",
                "user_uuid": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f"
              },
              "schema": {
                "properties": {
                  "refresh_token": {
                    "type": "string"
                  },
                  "user_uuid": {
                    "format": "uuid",
                    "type": "string"
                  }
                },
                "required": [
                  "refresh_token",
                  "user_uuid"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "token": {
                    "expiration_date": "2026-09-13T13:30:45Z",
                    "refresh_token": "rt_2f7c…",
                    "token": "eyJhbGciOiJFZERTQSJ9.e30.sig"
                  }
                },
                "schema": {
                  "properties": {
                    "token": {
                      "$ref": "#/components/schemas/Token"
                    }
                  },
                  "required": [
                    "token"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "New token pair"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Unknown, expired, used or revoked refresh token"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [],
        "summary": "Rotate a refresh token",
        "tags": [
          "auth"
        ]
      }
    },
    "/v1/auth/register": {
      "post": {
        "description": "Creates the organization and its first user (owner). On a self-hosted server `SIGNUP_MODE` governs it: `bootstrap` (default) accepts only the first signup, `closed` none, `open` any. The hosted edition creates accounts through its accounts service instead.",
        "operationId": "register",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "email": "ada@example.com",
                "full_name": "Ada Lovelace",
                "organization_name": "Analytical Engines",
                "password": "correct horse battery staple"
              },
              "schema": {
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "full_name": {
                    "type": "string"
                  },
                  "organization_name": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string"
                  },
                  "role_name": {
                    "description": "Ignored on public registration: the first user of an organization is its owner.",
                    "type": "string"
                  }
                },
                "required": [
                  "full_name",
                  "email",
                  "password",
                  "organization_name"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "token": {
                    "expiration_date": "2026-09-13T13:30:45Z",
                    "refresh_token": "rt_2f7c…",
                    "token": "eyJhbGciOiJFZERTQSJ9.e30.sig"
                  },
                  "user": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "email": "ada@example.com",
                    "email_verified": true,
                    "name": "Ada Lovelace",
                    "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                    "role_name": "admin",
                    "role_uuid": "7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
                    "status_uuid": "9d3f1e2c-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f"
                  }
                },
                "schema": {
                  "properties": {
                    "token": {
                      "$ref": "#/components/schemas/Token"
                    },
                    "user": {
                      "$ref": "#/components/schemas/SystemUser"
                    }
                  },
                  "required": [
                    "user",
                    "token"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Account created"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Invalid input"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Signup closed on this server (`signup_closed`)"
          },
          "409": {
            "content": {
              "application/json": {
                "example": {
                  "error": "already exists"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Email already registered"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [],
        "summary": "Create an account and its organization",
        "tags": [
          "auth"
        ]
      }
    },
    "/v1/boards": {
      "get": {
        "operationId": "listBoards",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "boards": [
                    {
                      "created_at": "2026-09-13T12:30:45Z",
                      "created_by": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                      "description": "Weekly growth metrics",
                      "name": "Growth",
                      "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                      "updated_at": "2026-09-13T12:30:45Z",
                      "uuid": "1b2c3d4e-5f60-4a1b-8c2d-3e4f5a6b7c8d",
                      "version": 3,
                      "visibility": "project",
                      "widget_count": 1
                    }
                  ]
                },
                "schema": {
                  "properties": {
                    "boards": {
                      "items": {
                        "$ref": "#/components/schemas/BoardSummary"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "boards"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "The project's boards and the caller's own private boards, without their definition"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Boards of the caller's project",
        "tags": [
          "boards"
        ]
      },
      "post": {
        "operationId": "createBoard",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "definition": {
                  "filters": [],
                  "match": "all",
                  "range": "7d",
                  "widgets": [
                    {
                      "breakdown": {
                        "property": "plan",
                        "scope": "event"
                      },
                      "id": "w1",
                      "interval": "day",
                      "kind": "line",
                      "metric": "total",
                      "series": [
                        {
                          "event": "signup",
                          "filters": [
                            {
                              "operator": "eq",
                              "property": "plan",
                              "scope": "event",
                              "values": [
                                "pro",
                                "growth"
                              ]
                            }
                          ],
                          "label": "Signups",
                          "match": "all"
                        }
                      ],
                      "size": "md",
                      "title": "Signups"
                    }
                  ]
                },
                "description": "Weekly growth metrics",
                "name": "Growth"
              },
              "schema": {
                "properties": {
                  "definition": {
                    "$ref": "#/components/schemas/BoardDefinition"
                  },
                  "description": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "visibility": {
                    "type": "string"
                  }
                },
                "required": [
                  "name"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "board": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "created_by": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                    "definition": {
                      "filters": [],
                      "match": "all",
                      "range": "7d",
                      "widgets": [
                        {
                          "breakdown": {
                            "property": "plan",
                            "scope": "event"
                          },
                          "id": "w1",
                          "interval": "day",
                          "kind": "line",
                          "metric": "total",
                          "series": [
                            {
                              "event": "signup",
                              "filters": [
                                {
                                  "operator": "eq",
                                  "property": "plan",
                                  "scope": "event",
                                  "values": [
                                    "pro",
                                    "growth"
                                  ]
                                }
                              ],
                              "label": "Signups",
                              "match": "all"
                            }
                          ],
                          "size": "md",
                          "title": "Signups"
                        }
                      ]
                    },
                    "description": "Weekly growth metrics",
                    "name": "Growth",
                    "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "1b2c3d4e-5f60-4a1b-8c2d-3e4f5a6b7c8d",
                    "version": 3,
                    "visibility": "project",
                    "widget_count": 1
                  }
                },
                "schema": {
                  "properties": {
                    "board": {
                      "$ref": "#/components/schemas/Board"
                    }
                  },
                  "required": [
                    "board"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Board created"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Caller is a viewer or holds project credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Create a board (any role but viewer)",
        "tags": [
          "boards"
        ]
      }
    },
    "/v1/boards/{board_uuid}": {
      "delete": {
        "operationId": "deleteBoard",
        "parameters": [
          {
            "in": "path",
            "name": "board_uuid",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                },
                "schema": {
                  "properties": {
                    "status": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Deleted"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Caller is a viewer or holds project credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No such board in this project, or another member's private board"
          },
          "409": {
            "content": {
              "application/json": {
                "example": {
                  "error": "already exists"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "The board was saved while it was being deleted; it was not deleted"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Delete a board (any role but viewer)",
        "tags": [
          "boards"
        ]
      },
      "get": {
        "operationId": "getBoard",
        "parameters": [
          {
            "in": "path",
            "name": "board_uuid",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "board": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "created_by": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                    "definition": {
                      "filters": [],
                      "match": "all",
                      "range": "7d",
                      "widgets": [
                        {
                          "breakdown": {
                            "property": "plan",
                            "scope": "event"
                          },
                          "id": "w1",
                          "interval": "day",
                          "kind": "line",
                          "metric": "total",
                          "series": [
                            {
                              "event": "signup",
                              "filters": [
                                {
                                  "operator": "eq",
                                  "property": "plan",
                                  "scope": "event",
                                  "values": [
                                    "pro",
                                    "growth"
                                  ]
                                }
                              ],
                              "label": "Signups",
                              "match": "all"
                            }
                          ],
                          "size": "md",
                          "title": "Signups"
                        }
                      ]
                    },
                    "description": "Weekly growth metrics",
                    "name": "Growth",
                    "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "1b2c3d4e-5f60-4a1b-8c2d-3e4f5a6b7c8d",
                    "version": 3,
                    "visibility": "project",
                    "widget_count": 1
                  }
                },
                "schema": {
                  "properties": {
                    "board": {
                      "$ref": "#/components/schemas/Board"
                    }
                  },
                  "required": [
                    "board"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Board"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No such board in this project"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One board with its definition",
        "tags": [
          "boards"
        ]
      },
      "put": {
        "operationId": "updateBoard",
        "parameters": [
          {
            "in": "path",
            "name": "board_uuid",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "definition": {
                  "filters": [],
                  "match": "all",
                  "range": "7d",
                  "widgets": [
                    {
                      "breakdown": {
                        "property": "plan",
                        "scope": "event"
                      },
                      "id": "w1",
                      "interval": "day",
                      "kind": "line",
                      "metric": "total",
                      "series": [
                        {
                          "event": "signup",
                          "filters": [
                            {
                              "operator": "eq",
                              "property": "plan",
                              "scope": "event",
                              "values": [
                                "pro",
                                "growth"
                              ]
                            }
                          ],
                          "label": "Signups",
                          "match": "all"
                        }
                      ],
                      "size": "md",
                      "title": "Signups"
                    }
                  ]
                },
                "description": "Weekly growth metrics",
                "name": "Growth",
                "version": 3
              },
              "schema": {
                "properties": {
                  "definition": {
                    "$ref": "#/components/schemas/BoardDefinition"
                  },
                  "description": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "version": {
                    "minimum": 0,
                    "type": "integer"
                  },
                  "visibility": {
                    "type": "string"
                  }
                },
                "required": [
                  "version",
                  "name",
                  "definition"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "board": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "created_by": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                    "definition": {
                      "filters": [],
                      "match": "all",
                      "range": "7d",
                      "widgets": [
                        {
                          "breakdown": {
                            "property": "plan",
                            "scope": "event"
                          },
                          "id": "w1",
                          "interval": "day",
                          "kind": "line",
                          "metric": "total",
                          "series": [
                            {
                              "event": "signup",
                              "filters": [
                                {
                                  "operator": "eq",
                                  "property": "plan",
                                  "scope": "event",
                                  "values": [
                                    "pro",
                                    "growth"
                                  ]
                                }
                              ],
                              "label": "Signups",
                              "match": "all"
                            }
                          ],
                          "size": "md",
                          "title": "Signups"
                        }
                      ]
                    },
                    "description": "Weekly growth metrics",
                    "name": "Growth",
                    "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "1b2c3d4e-5f60-4a1b-8c2d-3e4f5a6b7c8d",
                    "version": 3,
                    "visibility": "project",
                    "widget_count": 1
                  }
                },
                "schema": {
                  "properties": {
                    "board": {
                      "$ref": "#/components/schemas/Board"
                    }
                  },
                  "required": [
                    "board"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Updated; the board's version is one higher"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Caller is a viewer or holds project credentials, or is not the creator and tried to change visibility"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No such board in this project, or another member's private board"
          },
          "409": {
            "content": {
              "application/json": {
                "example": {
                  "error": "already exists"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "The board was saved since the given version; nothing was changed. Reload it and apply the edit again."
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Replace a board's name, description and definition (any role but viewer)",
        "tags": [
          "boards"
        ]
      }
    },
    "/v1/boards/{board_uuid}/widgets/{widget_id}/run": {
      "post": {
        "operationId": "runBoardWidget",
        "parameters": [
          {
            "in": "path",
            "name": "board_uuid",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "widget_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "end": "2026-09-13T12:30:45Z",
                "start": "2026-09-01T00:00:00Z"
              },
              "schema": {
                "properties": {
                  "end": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "start": {
                    "format": "date-time",
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "result": {
                    "end": "2026-09-13T12:30:45Z",
                    "funnel": {
                      "immature_users": 0,
                      "observed_until": "2026-09-13T12:30:45Z",
                      "overall_conversion_rate": null,
                      "steps": [],
                      "total_completed": 0,
                      "total_entered": 0,
                      "window_hours": 24
                    },
                    "start": "2026-09-01T00:00:00Z",
                    "type": "funnel",
                    "widget_id": "w_1a2b3c4d5e6f"
                  }
                },
                "schema": {
                  "properties": {
                    "result": {
                      "$ref": "#/components/schemas/BoardWidgetResult"
                    }
                  },
                  "required": [
                    "result"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "The report over [start, end) in the board's project, as its own route answers it"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "The widget is an Insights chart, the stored report no longer validates, or the window is invalid"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No such board or widget in this project, or another member's private board"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Run one saved funnel, retention or flow report of a board",
        "tags": [
          "boards"
        ]
      }
    },
    "/v1/cohorts": {
      "get": {
        "operationId": "listCohorts",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "cohorts": [
                    {
                      "created_at": "2026-09-13T12:30:45Z",
                      "created_by": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                      "definition": {
                        "match": "all",
                        "rules": [
                          {
                            "count": {
                              "operator": "gte",
                              "value": 2
                            },
                            "event": "purchase",
                            "type": "event",
                            "window": {
                              "last_days": 30
                            }
                          },
                          {
                            "filters": [
                              {
                                "operator": "ends_with",
                                "property": "$email",
                                "scope": "user",
                                "values": [
                                  "@example.com"
                                ]
                              }
                            ],
                            "negate": true,
                            "type": "property"
                          }
                        ],
                        "schema": "cohort/1"
                      },
                      "description": "",
                      "name": "Engaged buyers",
                      "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                      "updated_at": "2026-09-13T12:30:45Z",
                      "uuid": "2c3d4e5f-6071-4b2c-9d3e-4f5a6b7c8d9e",
                      "version": 2
                    }
                  ]
                },
                "schema": {
                  "properties": {
                    "cohorts": {
                      "items": {
                        "$ref": "#/components/schemas/Cohort"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "cohorts"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "The project's cohorts with their definitions"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Saved cohorts of the caller's project",
        "tags": [
          "cohorts"
        ]
      },
      "post": {
        "operationId": "createCohort",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "definition": {
                  "match": "all",
                  "rules": [
                    {
                      "count": {
                        "operator": "gte",
                        "value": 2
                      },
                      "event": "purchase",
                      "type": "event",
                      "window": {
                        "last_days": 30
                      }
                    },
                    {
                      "filters": [
                        {
                          "operator": "ends_with",
                          "property": "$email",
                          "scope": "user",
                          "values": [
                            "@example.com"
                          ]
                        }
                      ],
                      "negate": true,
                      "type": "property"
                    }
                  ],
                  "schema": "cohort/1"
                },
                "description": "",
                "name": "Engaged buyers"
              },
              "schema": {
                "properties": {
                  "definition": {
                    "$ref": "#/components/schemas/CohortDefinition"
                  },
                  "description": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  }
                },
                "required": [
                  "name",
                  "definition"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "cohort": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "created_by": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                    "definition": {
                      "match": "all",
                      "rules": [
                        {
                          "count": {
                            "operator": "gte",
                            "value": 2
                          },
                          "event": "purchase",
                          "type": "event",
                          "window": {
                            "last_days": 30
                          }
                        },
                        {
                          "filters": [
                            {
                              "operator": "ends_with",
                              "property": "$email",
                              "scope": "user",
                              "values": [
                                "@example.com"
                              ]
                            }
                          ],
                          "negate": true,
                          "type": "property"
                        }
                      ],
                      "schema": "cohort/1"
                    },
                    "description": "",
                    "name": "Engaged buyers",
                    "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "2c3d4e5f-6071-4b2c-9d3e-4f5a6b7c8d9e",
                    "version": 2
                  }
                },
                "schema": {
                  "properties": {
                    "cohort": {
                      "$ref": "#/components/schemas/Cohort"
                    }
                  },
                  "required": [
                    "cohort"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Cohort saved"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "The definition is invalid, too large, or its references are circular or more than 3 deep"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Caller is a viewer or holds project credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "A referenced cohort is not in this project"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Save a cohort (any role but viewer)",
        "tags": [
          "cohorts"
        ]
      }
    },
    "/v1/cohorts/preview": {
      "post": {
        "operationId": "previewCohort",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "definition": {
                  "match": "all",
                  "rules": [
                    {
                      "count": {
                        "operator": "gte",
                        "value": 2
                      },
                      "event": "purchase",
                      "type": "event",
                      "window": {
                        "last_days": 30
                      }
                    },
                    {
                      "filters": [
                        {
                          "operator": "ends_with",
                          "property": "$email",
                          "scope": "user",
                          "values": [
                            "@example.com"
                          ]
                        }
                      ],
                      "negate": true,
                      "type": "property"
                    }
                  ],
                  "schema": "cohort/1"
                }
              },
              "schema": {
                "properties": {
                  "cohort_uuid": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "definition": {
                    "$ref": "#/components/schemas/CohortDefinition"
                  }
                },
                "required": [
                  "definition"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "as_of": "2026-09-13T12:30:45Z",
                  "count": 412
                },
                "schema": {
                  "$ref": "#/components/schemas/CohortCount"
                }
              }
            },
            "description": "The exact member count at as_of"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "The definition is invalid"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Count an unsaved cohort definition's members now",
        "tags": [
          "cohorts"
        ]
      }
    },
    "/v1/cohorts/{cohort_uuid}": {
      "delete": {
        "operationId": "deleteCohort",
        "parameters": [
          {
            "in": "path",
            "name": "cohort_uuid",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                },
                "schema": {
                  "properties": {
                    "status": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Deleted"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No such cohort in this project"
          },
          "409": {
            "content": {
              "application/json": {
                "example": {
                  "error": "already exists"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Another cohort or a board still uses it (the message names them), or it was saved while being deleted"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Delete a cohort (any role but viewer)",
        "tags": [
          "cohorts"
        ]
      },
      "get": {
        "operationId": "getCohort",
        "parameters": [
          {
            "in": "path",
            "name": "cohort_uuid",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "cohort": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "created_by": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                    "definition": {
                      "match": "all",
                      "rules": [
                        {
                          "count": {
                            "operator": "gte",
                            "value": 2
                          },
                          "event": "purchase",
                          "type": "event",
                          "window": {
                            "last_days": 30
                          }
                        },
                        {
                          "filters": [
                            {
                              "operator": "ends_with",
                              "property": "$email",
                              "scope": "user",
                              "values": [
                                "@example.com"
                              ]
                            }
                          ],
                          "negate": true,
                          "type": "property"
                        }
                      ],
                      "schema": "cohort/1"
                    },
                    "description": "",
                    "name": "Engaged buyers",
                    "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "2c3d4e5f-6071-4b2c-9d3e-4f5a6b7c8d9e",
                    "version": 2
                  }
                },
                "schema": {
                  "properties": {
                    "cohort": {
                      "$ref": "#/components/schemas/Cohort"
                    }
                  },
                  "required": [
                    "cohort"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Cohort"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No such cohort in this project"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One cohort with its definition",
        "tags": [
          "cohorts"
        ]
      },
      "put": {
        "operationId": "updateCohort",
        "parameters": [
          {
            "in": "path",
            "name": "cohort_uuid",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "definition": {
                  "match": "all",
                  "rules": [
                    {
                      "count": {
                        "operator": "gte",
                        "value": 2
                      },
                      "event": "purchase",
                      "type": "event",
                      "window": {
                        "last_days": 30
                      }
                    },
                    {
                      "filters": [
                        {
                          "operator": "ends_with",
                          "property": "$email",
                          "scope": "user",
                          "values": [
                            "@example.com"
                          ]
                        }
                      ],
                      "negate": true,
                      "type": "property"
                    }
                  ],
                  "schema": "cohort/1"
                },
                "description": "",
                "name": "Engaged buyers",
                "version": 2
              },
              "schema": {
                "properties": {
                  "definition": {
                    "$ref": "#/components/schemas/CohortDefinition"
                  },
                  "description": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "version": {
                    "minimum": 0,
                    "type": "integer"
                  }
                },
                "required": [
                  "version",
                  "name",
                  "definition"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "cohort": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "created_by": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                    "definition": {
                      "match": "all",
                      "rules": [
                        {
                          "count": {
                            "operator": "gte",
                            "value": 2
                          },
                          "event": "purchase",
                          "type": "event",
                          "window": {
                            "last_days": 30
                          }
                        },
                        {
                          "filters": [
                            {
                              "operator": "ends_with",
                              "property": "$email",
                              "scope": "user",
                              "values": [
                                "@example.com"
                              ]
                            }
                          ],
                          "negate": true,
                          "type": "property"
                        }
                      ],
                      "schema": "cohort/1"
                    },
                    "description": "",
                    "name": "Engaged buyers",
                    "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "2c3d4e5f-6071-4b2c-9d3e-4f5a6b7c8d9e",
                    "version": 2
                  }
                },
                "schema": {
                  "properties": {
                    "cohort": {
                      "$ref": "#/components/schemas/Cohort"
                    }
                  },
                  "required": [
                    "cohort"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Updated; the cohort's version is one higher"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "The definition is invalid or makes references circular"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No such cohort in this project"
          },
          "409": {
            "content": {
              "application/json": {
                "example": {
                  "error": "already exists"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "The cohort was saved since the given version; nothing was changed"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Replace a cohort's name, description and definition (any role but viewer)",
        "tags": [
          "cohorts"
        ]
      }
    },
    "/v1/cohorts/{cohort_uuid}/members": {
      "get": {
        "operationId": "getCohortMembers",
        "parameters": [
          {
            "in": "path",
            "name": "cohort_uuid",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 50,
              "maximum": 500,
              "minimum": 1,
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "schema": {
              "default": 0,
              "minimum": 0,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "as_of": "2026-09-13T12:30:45Z",
                  "count": 412,
                  "limit": 50,
                  "members": [
                    {
                      "created_at": "2026-09-13T12:30:45Z",
                      "custom_id": "user_12345",
                      "email": "ada@example.com",
                      "events_count": 42,
                      "name": "Ada Lovelace",
                      "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                      "properties": {
                        "plan": "pro"
                      },
                      "updated_at": "2026-09-13T12:30:45Z",
                      "uuid": "00000000-0000-0000-8b20-15635fadf462"
                    }
                  ],
                  "offset": 0
                },
                "schema": {
                  "$ref": "#/components/schemas/CohortMembers"
                }
              }
            },
            "description": "Members at as_of"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No such cohort in this project"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "A cohort's exact count and one page of members, most recently active first",
        "tags": [
          "cohorts"
        ]
      }
    },
    "/v1/events/batch": {
      "post": {
        "description": "Events are validated as a whole and accepted or refused as a whole. 202 means the whole batch is durably accepted (fsynced to the api's ingest log) and will reach analytics within about a second while ClickHouse is up; it does not mean the events are already queryable. 503 with Retry-After means nothing was accepted; retry the same batch. Items whose message_id was already accepted are answered as accepted and not stored again, so resending a batch is safe. All events of one batch belong to the user named by X-User-Id. Batching is the cheap path: one request for many events.",
        "operationId": "trackEventsBatch",
        "parameters": [
          {
            "description": "Who the event belongs to: your user id, or a per-visitor anonymous id you keep (the SDKs generate one). Same namespace as identify's custom_id. Omit only when a shared, address-derived profile is acceptable.",
            "in": "header",
            "name": "X-User-Id",
            "schema": {
              "maxLength": 256,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "events": [
                  {
                    "created_at": "2026-09-13T12:30:45Z",
                    "name": "screen_view",
                    "properties": {
                      "screen": "home"
                    },
                    "type": "track"
                  },
                  {
                    "created_at": "2026-09-13T12:30:47Z",
                    "name": "button_tap",
                    "properties": {
                      "button": "buy"
                    },
                    "type": "track"
                  }
                ]
              },
              "schema": {
                "properties": {
                  "anonymous_id": {
                    "description": "The device's anonymous id (anon_...), kept after identify so destinations can merge the anonymous history. Forwarded to IForevents Cloud destinations; not stored.",
                    "type": "string"
                  },
                  "context": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/ClientContext"
                      }
                    ],
                    "description": "What the SDK knows about the device and app. Unknown members are dropped, strings are cut at 256 characters, and a context that does not decode is ignored. Forwarded to IForevents Cloud destinations; not stored."
                  },
                  "events": {
                    "items": {
                      "$ref": "#/components/schemas/EventData"
                    },
                    "type": "array"
                  },
                  "message_id": {
                    "description": "The SDK's id for the call, a UUID made once per call and kept across retries (on a batch, each item carries its own). The api deduplicates on it for 24 hours: a resent call with the same id and content is answered as accepted and stored once; the same id with different content is refused with 409 event_id_conflict. Forwarded to IForevents Cloud destinations.",
                    "type": "string"
                  },
                  "sent_at": {
                    "description": "When the SDK sent the request (RFC 3339), on the device's clock. Forwarded to IForevents Cloud destinations; not stored.",
                    "type": "string"
                  }
                },
                "required": [
                  "events"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "status": "queued",
                  "user_uuid": "00000000-0000-0000-8b20-15635fadf462"
                },
                "schema": {
                  "properties": {
                    "status": {
                      "enum": [
                        "queued"
                      ],
                      "type": "string"
                    },
                    "user_uuid": {
                      "format": "uuid",
                      "type": "string"
                    }
                  },
                  "required": [
                    "status",
                    "user_uuid"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Queued"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Unknown project key"
          },
          "402": {
            "content": {
              "application/json": {
                "example": {
                  "error": "request failed"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "storage_budget_exceeded: the project has stored its plan's budget of logical bytes (free plan); nothing accepted, do not retry until the plan changes or the retention window or an erasure frees space (docs/STORAGE_BUDGET.md)"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "The user was erased (event_erased) or withdrew analytics consent (purpose_denied); nothing accepted, do not retry"
          },
          "409": {
            "content": {
              "application/json": {
                "example": {
                  "error": "already exists"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "message_id already used for a different event (event_id_conflict); nothing accepted"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Plan event quota or rate limit exceeded"
          },
          "503": {
            "content": {
              "application/json": {
                "example": {
                  "error": "not ready"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Ingestion at capacity, or an earlier request with the same message_id is still running (event_in_flight); nothing accepted (Retry-After set). event_bus_unavailable: the copy for Cloud destinations could not be queued; the events may already be stored, retry (a retry may store them twice, never loses them)"
          }
        },
        "security": [
          {
            "projectKey": []
          }
        ],
        "summary": "Queue up to 500 events",
        "tags": [
          "ingest"
        ]
      }
    },
    "/v1/events/identify": {
      "post": {
        "description": "Upserts the profile identified by custom_id: your own id for the person, the same value track and batch take in X-User-Id. Events sent under that id before the first identify already belong to the profile; identify only adds the name, e-mail and properties. It stores no event and does not count against the plan's events.",
        "operationId": "identifyUser",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "custom_id": "user_12345",
                "email": "ada@example.com",
                "name": "Ada Lovelace",
                "properties": {
                  "plan": "pro"
                }
              },
              "schema": {
                "properties": {
                  "anonymous_id": {
                    "description": "The device's anonymous id (anon_...), kept after identify so destinations can merge the anonymous history. Forwarded to IForevents Cloud destinations; not stored.",
                    "type": "string"
                  },
                  "context": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/ClientContext"
                      }
                    ],
                    "description": "What the SDK knows about the device and app. Unknown members are dropped, strings are cut at 256 characters, and a context that does not decode is ignored. Forwarded to IForevents Cloud destinations; not stored."
                  },
                  "custom_id": {
                    "description": "Your identifier for the user; identifies the same profile on every call.",
                    "type": "string"
                  },
                  "email": {
                    "type": "string"
                  },
                  "message_id": {
                    "description": "The SDK's id for the call, a UUID made once per call and kept across retries (on a batch, each item carries its own). The api deduplicates on it for 24 hours: a resent call with the same id and content is answered as accepted and stored once; the same id with different content is refused with 409 event_id_conflict. Forwarded to IForevents Cloud destinations.",
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "phone_number": {
                    "type": "string"
                  },
                  "properties": {
                    "additionalProperties": true,
                    "type": "object"
                  },
                  "sent_at": {
                    "description": "When the SDK sent the request (RFC 3339), on the device's clock. Forwarded to IForevents Cloud destinations; not stored.",
                    "type": "string"
                  }
                },
                "required": [
                  "custom_id"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "user": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "custom_id": "user_12345",
                    "email": "ada@example.com",
                    "events_count": 42,
                    "name": "Ada Lovelace",
                    "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                    "properties": {
                      "plan": "pro"
                    },
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "00000000-0000-0000-8b20-15635fadf462"
                  }
                },
                "schema": {
                  "properties": {
                    "user": {
                      "$ref": "#/components/schemas/User"
                    }
                  },
                  "required": [
                    "user"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Profile stored"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Unknown project key"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "The user was erased (event_erased) or withdrew profile_enrichment consent (purpose_denied); nothing stored"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Plan event quota or rate limit exceeded"
          },
          "503": {
            "content": {
              "application/json": {
                "example": {
                  "error": "not ready"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "event_bus_unavailable: the profile is stored but its copy for Cloud destinations could not be queued; retry (Retry-After set)"
          }
        },
        "security": [
          {
            "projectKey": []
          }
        ],
        "summary": "Create or update a tracked user",
        "tags": [
          "ingest"
        ]
      }
    },
    "/v1/events/track": {
      "post": {
        "description": "Records a single event for the project identified by X-Project-Key. X-User-Id names the person: your own user id, or an anonymous id you generate and keep per visitor; the user exists by its events, no identify call needed (identify only adds a profile). Without the header the event is filed under a profile derived from the source address and User-Agent, which merges every caller behind one server, proxy or NAT into a single user. 201 means the event is durably accepted: written and fsynced to the api's ingest log, from which it reaches analytics within about a second while ClickHouse is up. It does not mean the event is already queryable. 503 with Retry-After means nothing was accepted; retry. A retry with the same message_id is stored once (docs/EVENT_IDENTITY.md).",
        "operationId": "trackEvent",
        "parameters": [
          {
            "description": "Who the event belongs to: your user id, or a per-visitor anonymous id you keep (the SDKs generate one). Same namespace as identify's custom_id. Omit only when a shared, address-derived profile is acceptable.",
            "in": "header",
            "name": "X-User-Id",
            "schema": {
              "maxLength": 256,
              "minLength": 1,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "event_name": "checkout_completed",
                "event_type": "track",
                "properties": {
                  "items": 3,
                  "order_id": "ord_456",
                  "total": 99.99
                }
              },
              "schema": {
                "properties": {
                  "anonymous_id": {
                    "description": "The device's anonymous id (anon_...), kept after identify so destinations can merge the anonymous history. Forwarded to IForevents Cloud destinations; not stored.",
                    "type": "string"
                  },
                  "context": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/ClientContext"
                      }
                    ],
                    "description": "What the SDK knows about the device and app. Unknown members are dropped, strings are cut at 256 characters, and a context that does not decode is ignored. Forwarded to IForevents Cloud destinations; not stored."
                  },
                  "created_at": {
                    "description": "When the event happened (RFC 3339), on your clock. Optional: absent means when the api received it. A time more than an hour ahead is replaced by the receive time. Part of the message_id fingerprint, so send the same value on a retry.",
                    "format": "date-time",
                    "type": "string"
                  },
                  "event_name": {
                    "description": "Event name, for example checkout_completed.",
                    "type": "string"
                  },
                  "event_type": {
                    "description": "Defaults to track. page_view and screen are stored as page views; group and alias are not stored or counted as events and only reach the Cloud destinations, like identify.",
                    "enum": [
                      "track",
                      "page_view",
                      "screen",
                      "group",
                      "alias"
                    ],
                    "type": "string"
                  },
                  "group_id": {
                    "description": "Required when event_type is group: the account the user belongs to. properties are the account's traits.",
                    "type": "string"
                  },
                  "message_id": {
                    "description": "The SDK's id for the call, a UUID made once per call and kept across retries (on a batch, each item carries its own). The api deduplicates on it for 24 hours: a resent call with the same id and content is answered as accepted and stored once; the same id with different content is refused with 409 event_id_conflict. Forwarded to IForevents Cloud destinations.",
                    "type": "string"
                  },
                  "previous_id": {
                    "description": "Required when event_type is alias: the earlier id that X-User-Id now replaces.",
                    "type": "string"
                  },
                  "properties": {
                    "additionalProperties": true,
                    "type": "object"
                  },
                  "sent_at": {
                    "description": "When the SDK sent the request (RFC 3339), on the device's clock. Forwarded to IForevents Cloud destinations; not stored.",
                    "type": "string"
                  }
                },
                "required": [
                  "event_name"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "user_uuid": "00000000-0000-0000-8b20-15635fadf462"
                },
                "schema": {
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "user_uuid": {
                      "format": "uuid",
                      "type": "string"
                    }
                  },
                  "required": [
                    "status",
                    "user_uuid"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Recorded"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Unknown project key"
          },
          "402": {
            "content": {
              "application/json": {
                "example": {
                  "error": "request failed"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "storage_budget_exceeded: the project has stored its plan's budget of logical bytes (free plan); nothing accepted, do not retry until the plan changes or the retention window or an erasure frees space (docs/STORAGE_BUDGET.md)"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "The user was erased (event_erased) or withdrew analytics consent (purpose_denied); nothing accepted, do not retry"
          },
          "409": {
            "content": {
              "application/json": {
                "example": {
                  "error": "already exists"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "message_id already used for a different event (event_id_conflict); nothing accepted"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Plan event quota or rate limit exceeded"
          },
          "503": {
            "content": {
              "application/json": {
                "example": {
                  "error": "not ready"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Ingestion at capacity, or an earlier request with the same message_id is still running (event_in_flight); nothing accepted (Retry-After set). event_bus_unavailable: the copy for Cloud destinations could not be queued; the events may already be stored, retry (a retry may store them twice, never loses them)"
          }
        },
        "security": [
          {
            "projectKey": []
          }
        ],
        "summary": "Record one event",
        "tags": [
          "ingest"
        ]
      }
    },
    "/v1/imports": {
      "post": {
        "description": "Moves a project between organizations without a download: the caller must be an admin of the export's organization (by current membership) and of the organization its token names, where the project is recreated. A new project is created unless target.project_uuid names an empty one; its secret is shown in this response only. Cohorts and boards get new ids with their references remapped, the caller becomes their author, and events keep their timestamps.",
        "operationId": "createImportFromExport",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "export_uuid": "7a9b0c1d-2e3f-4a5b-8c6d-7e8f9a0b1c2d",
                "source_organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                "target": {
                  "project_name": "Mobile app"
                }
              },
              "schema": {
                "properties": {
                  "export_uuid": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "source_organization_uuid": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "target": {
                    "$ref": "#/components/schemas/ImportTarget"
                  }
                },
                "required": [
                  "source_organization_uuid",
                  "export_uuid"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "notice": "store the project secret now; it is not shown again",
                  "project": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "data_residency": "US",
                    "key": "3142566d8c88721d6d34bd9443d556bf",
                    "name": "Mobile app",
                    "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                    "secret": "ps_9c0f…",
                    "selected": true,
                    "status_uuid": "9d3f1e2c-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f"
                  },
                  "project_created": true,
                  "transfer": {
                    "bundle_bytes": 0,
                    "bundle_deleted": false,
                    "created_at": "2026-09-13T12:30:45Z",
                    "created_by": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                    "kind": "import",
                    "options": {
                      "include_events": true
                    },
                    "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                    "progress": {
                      "boards": 3,
                      "cohorts": 2,
                      "event_part_rows": 0,
                      "event_parts_done": 0,
                      "events_done": 450000,
                      "events_total": 1200000,
                      "phase": "events",
                      "users_done": 8000,
                      "users_total": 8000
                    },
                    "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                    "started_at": "2026-09-13T12:30:45Z",
                    "status": "queued",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "7a9b0c1d-2e3f-4a5b-8c6d-7e8f9a0b1c2d"
                  }
                },
                "schema": {
                  "properties": {
                    "notice": {
                      "description": "Present when a project was created: its secret is shown this once",
                      "type": "string"
                    },
                    "project": {
                      "$ref": "#/components/schemas/Project"
                    },
                    "project_created": {
                      "type": "boolean"
                    },
                    "transfer": {
                      "$ref": "#/components/schemas/TransferJob"
                    }
                  },
                  "required": [
                    "transfer",
                    "project",
                    "project_created"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Import queued"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No such export, or the caller does not administer its organization"
          },
          "409": {
            "content": {
              "application/json": {
                "example": {
                  "error": "already exists"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "The export has not finished, or the target project already has events"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Import another organization's export into this one (admin of both)",
        "tags": [
          "transfers"
        ]
      }
    },
    "/v1/imports/upload": {
      "post": {
        "description": "The request body is the bundle file exactly as downloaded. It is written to disk as it arrives and checked by the import job, which refuses a bundle whose checksums do not match before storing anything.",
        "operationId": "uploadImportBundle",
        "parameters": [
          {
            "description": "An empty project of this organization to import into; omitted creates a project",
            "in": "query",
            "name": "project_uuid",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "Name of the created project; defaults to the bundle's",
            "in": "query",
            "name": "project_name",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "data_residency",
            "schema": {
              "enum": [
                "US",
                "EU"
              ],
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "allow_non_empty",
            "schema": {
              "default": false,
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/octet-stream": {
              "example": "<bundle bytes>",
              "schema": {
                "format": "binary",
                "type": "string"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "notice": "store the project secret now; it is not shown again",
                  "project": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "data_residency": "US",
                    "key": "3142566d8c88721d6d34bd9443d556bf",
                    "name": "Mobile app",
                    "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                    "secret": "ps_9c0f…",
                    "selected": true,
                    "status_uuid": "9d3f1e2c-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f"
                  },
                  "project_created": true,
                  "transfer": {
                    "bundle_bytes": 0,
                    "bundle_deleted": false,
                    "created_at": "2026-09-13T12:30:45Z",
                    "created_by": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                    "kind": "import",
                    "options": {
                      "include_events": true
                    },
                    "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                    "progress": {
                      "boards": 3,
                      "cohorts": 2,
                      "event_part_rows": 0,
                      "event_parts_done": 0,
                      "events_done": 450000,
                      "events_total": 1200000,
                      "phase": "events",
                      "users_done": 8000,
                      "users_total": 8000
                    },
                    "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                    "started_at": "2026-09-13T12:30:45Z",
                    "status": "queued",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "7a9b0c1d-2e3f-4a5b-8c6d-7e8f9a0b1c2d"
                  }
                },
                "schema": {
                  "properties": {
                    "notice": {
                      "description": "Present when a project was created: its secret is shown this once",
                      "type": "string"
                    },
                    "project": {
                      "$ref": "#/components/schemas/Project"
                    },
                    "project_created": {
                      "type": "boolean"
                    },
                    "transfer": {
                      "$ref": "#/components/schemas/TransferJob"
                    }
                  },
                  "required": [
                    "transfer",
                    "project",
                    "project_created"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Import queued"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Not a bundle, empty, or larger than TRANSFER_MAX_UPLOAD_MB"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "409": {
            "content": {
              "application/json": {
                "example": {
                  "error": "already exists"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "The target project already has events"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Import an uploaded bundle (admin only)",
        "tags": [
          "transfers"
        ]
      }
    },
    "/v1/privacy/consent": {
      "get": {
        "operationId": "getConsent",
        "parameters": [
          {
            "in": "query",
            "name": "user_id",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "user_uuid",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "history": [
                    {
                      "actor": "project_credentials",
                      "purpose": "analytics",
                      "recorded_at": "2026-09-13T12:30:45Z",
                      "source": "cookie_banner",
                      "state": "withdrawn"
                    }
                  ],
                  "history_truncated": false,
                  "purposes": [
                    {
                      "actor": "project_credentials",
                      "enforced": true,
                      "purpose": "analytics",
                      "recorded_at": "2026-09-13T12:30:45Z",
                      "source": "cookie_banner",
                      "state": "withdrawn"
                    },
                    {
                      "enforced": false,
                      "purpose": "profile_enrichment",
                      "state": "unknown"
                    }
                  ],
                  "suppressions": [
                    {
                      "created_at": "2026-09-13T12:30:45Z",
                      "reason": "consent_withdrawn:analytics",
                      "user_id": "user_12345"
                    }
                  ],
                  "user_id": "user_12345",
                  "user_uuid": "00000000-0000-0000-8b20-15635fadf462"
                },
                "schema": {
                  "$ref": "#/components/schemas/SubjectConsent"
                }
              }
            },
            "description": "Every purpose (unknown when nothing was recorded: processing is allowed), the suppressions and the newest 200 ledger rows"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No user named"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "A user's consent per purpose, its enforcement and the ledger",
        "tags": [
          "privacy"
        ]
      },
      "put": {
        "operationId": "setConsent",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "purpose": "analytics",
                "source": "cookie_banner",
                "state": "withdrawn",
                "user_id": "user_12345"
              },
              "schema": {
                "properties": {
                  "purpose": {
                    "enum": [
                      "analytics",
                      "profile_enrichment",
                      "audience_activation",
                      "session_replay",
                      "ai_analysis"
                    ],
                    "type": "string"
                  },
                  "source": {
                    "description": "Where the decision came from (default api)",
                    "maxLength": 64,
                    "type": "string"
                  },
                  "state": {
                    "enum": [
                      "granted",
                      "withdrawn"
                    ],
                    "type": "string"
                  },
                  "user_id": {
                    "description": "The id the user is tracked with (X-User-Id); or user_uuid",
                    "type": "string"
                  },
                  "user_uuid": {
                    "format": "uuid",
                    "type": "string"
                  }
                },
                "required": [
                  "purpose",
                  "state"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "history": [
                    {
                      "actor": "project_credentials",
                      "purpose": "analytics",
                      "recorded_at": "2026-09-13T12:30:45Z",
                      "source": "cookie_banner",
                      "state": "withdrawn"
                    }
                  ],
                  "history_truncated": false,
                  "purposes": [
                    {
                      "actor": "project_credentials",
                      "enforced": true,
                      "purpose": "analytics",
                      "recorded_at": "2026-09-13T12:30:45Z",
                      "source": "cookie_banner",
                      "state": "withdrawn"
                    },
                    {
                      "enforced": false,
                      "purpose": "profile_enrichment",
                      "state": "unknown"
                    }
                  ],
                  "suppressions": [
                    {
                      "created_at": "2026-09-13T12:30:45Z",
                      "reason": "consent_withdrawn:analytics",
                      "user_id": "user_12345"
                    }
                  ],
                  "user_id": "user_12345",
                  "user_uuid": "00000000-0000-0000-8b20-15635fadf462"
                },
                "schema": {
                  "$ref": "#/components/schemas/SubjectConsent"
                }
              }
            },
            "description": "Recorded. A withdrawal installs its suppression first; withdrawing analytics also removes the user's events and their share of every aggregate, withdrawing profile_enrichment the profile. A grant lifts the withdrawal for new data only."
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Unknown purpose or state, or no user named"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "A viewer, or project credentials granting (they may only withdraw)"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "projectKey": [],
            "projectSecret": []
          }
        ],
        "summary": "Record a user's consent decision for one purpose",
        "tags": [
          "privacy"
        ]
      }
    },
    "/v1/privacy/subjects/{user_uuid}": {
      "delete": {
        "operationId": "eraseSubject",
        "parameters": [
          {
            "in": "path",
            "name": "user_uuid",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "custom_id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "physical_purge": "pending",
                  "purge": {
                    "aggregates": "rebuilt",
                    "live_rows_remaining": {
                      "events": 0,
                      "session_metrics": 0,
                      "users": 0
                    },
                    "physical_rows_remaining": {
                      "events": 12,
                      "session_metrics": 2,
                      "users": 1
                    }
                  },
                  "status": "erased",
                  "suppression": "active",
                  "user_uuid": "00000000-0000-0000-8b20-15635fadf462"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErasureReport"
                }
              }
            },
            "description": "The erasure suppression is active (later ingest of the user is refused with event_erased) and the profile, events, daily activity, per-day counts and property values no longer show the user. status is incomplete when something is still visible; physical_purge is complete once the queued rewrite removed the rows from disk (backups excluded, docs/PRIVACY.md)."
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Caller is not an admin"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No such user in this organization"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Erase a tracked user: suppression first, then every api-owned copy (admin only)",
        "tags": [
          "privacy"
        ]
      },
      "get": {
        "operationId": "exportSubject",
        "parameters": [
          {
            "in": "path",
            "name": "user_uuid",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "subject": {
                    "events": [
                      {
                        "created_at": "2026-09-13T12:30:45Z",
                        "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                        "parent_name": "checkout_completed",
                        "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                        "properties": {
                          "order_id": "ord_456",
                          "total": "99.99"
                        },
                        "type": "track",
                        "user_uuid": "00000000-0000-0000-8b20-15635fadf462",
                        "uuid": "00000000-0000-0000-3c9e-5b7a1d24f086"
                      }
                    ],
                    "user": {
                      "created_at": "2026-09-13T12:30:45Z",
                      "custom_id": "user_12345",
                      "email": "ada@example.com",
                      "events_count": 42,
                      "name": "Ada Lovelace",
                      "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                      "properties": {
                        "plan": "pro"
                      },
                      "updated_at": "2026-09-13T12:30:45Z",
                      "uuid": "00000000-0000-0000-8b20-15635fadf462"
                    }
                  }
                },
                "schema": {
                  "properties": {
                    "subject": {
                      "$ref": "#/components/schemas/SubjectExport"
                    }
                  },
                  "required": [
                    "subject"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Profile and events"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No such user in this organization"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Export everything stored about one tracked user",
        "tags": [
          "privacy"
        ]
      }
    },
    "/v1/privacy/subjects/{user_uuid}/erasure": {
      "get": {
        "operationId": "getErasureStatus",
        "parameters": [
          {
            "in": "path",
            "name": "user_uuid",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "custom_id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "physical_purge": "pending",
                  "purge": {
                    "aggregates": "rebuilt",
                    "live_rows_remaining": {
                      "events": 0,
                      "session_metrics": 0,
                      "users": 0
                    },
                    "physical_rows_remaining": {
                      "events": 12,
                      "session_metrics": 2,
                      "users": 1
                    }
                  },
                  "status": "erased",
                  "suppression": "active",
                  "user_uuid": "00000000-0000-0000-8b20-15635fadf462"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErasureReport"
                }
              }
            },
            "description": "Suppression state (active, lifted, none) and remaining rows per store"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No such project"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "What is left of an erased user, live and on disk",
        "tags": [
          "privacy"
        ]
      }
    },
    "/v1/privacy/suppressions/lift": {
      "post": {
        "operationId": "liftSuppression",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "confirm": "00000000-0000-0000-8b20-15635fadf462",
                "reason": "erased",
                "user_uuid": "00000000-0000-0000-8b20-15635fadf462"
              },
              "schema": {
                "properties": {
                  "confirm": {
                    "description": "The user's user_uuid, repeated",
                    "format": "uuid",
                    "type": "string"
                  },
                  "reason": {
                    "enum": [
                      "erased"
                    ],
                    "type": "string"
                  },
                  "user_id": {
                    "type": "string"
                  },
                  "user_uuid": {
                    "format": "uuid",
                    "type": "string"
                  }
                },
                "required": [
                  "reason",
                  "confirm"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "suppressions": [],
                  "user_uuid": "00000000-0000-0000-8b20-15635fadf462"
                },
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": "Lifted; later events of the user are accepted again"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "confirm does not repeat the user's uuid, or a consent reason (lifted by a grant)"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Not a verified admin"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No active erasure suppression"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Lift an erasure suppression (admin recovery; erased data stays erased)",
        "tags": [
          "privacy"
        ]
      }
    },
    "/v1/projects": {
      "post": {
        "description": "The response is the only time the project secret is shown.",
        "operationId": "createProject",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "name": "Mobile app"
              },
              "schema": {
                "properties": {
                  "data_residency": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  }
                },
                "required": [
                  "name"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "notice": "store the secret now; it is not shown again",
                  "project": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "data_residency": "US",
                    "key": "3142566d8c88721d6d34bd9443d556bf",
                    "name": "Mobile app",
                    "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                    "secret": "ps_9c0f…",
                    "selected": true,
                    "status_uuid": "9d3f1e2c-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f"
                  }
                },
                "schema": {
                  "properties": {
                    "notice": {
                      "type": "string"
                    },
                    "project": {
                      "$ref": "#/components/schemas/Project"
                    }
                  },
                  "required": [
                    "project",
                    "notice"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Project with its one-time secret"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "402": {
            "content": {
              "application/json": {
                "example": {
                  "error": "request failed"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "project_limit_reached: the organization has as many enabled projects as its plan allows (projects_per_org)"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Caller is not an admin or email unverified"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Create a project (admin only)",
        "tags": [
          "projects"
        ]
      }
    },
    "/v1/projects/{project_uuid}": {
      "patch": {
        "operationId": "updateProject",
        "parameters": [
          {
            "$ref": "#/components/parameters/projectUUID"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "name": "Mobile app (iOS)"
              },
              "schema": {
                "properties": {
                  "name": {
                    "type": "string"
                  }
                },
                "required": [
                  "name"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "project": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "data_residency": "US",
                    "key": "3142566d8c88721d6d34bd9443d556bf",
                    "name": "Mobile app (iOS)",
                    "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                    "selected": true,
                    "status_uuid": "9d3f1e2c-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f"
                  }
                },
                "schema": {
                  "properties": {
                    "project": {
                      "$ref": "#/components/schemas/Project"
                    }
                  },
                  "required": [
                    "project"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Updated"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Project not found in this organization"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Rename a project (admin only)",
        "tags": [
          "projects"
        ]
      }
    },
    "/v1/projects/{project_uuid}/exports": {
      "post": {
        "description": "Queues an export job and answers at once. The job writes the project, its cohorts and boards and (unless include_events is false) its profiles and events to a bundle file, reading in bounded chunks under a rows-per-second budget so the api stays responsive. Poll GET /v1/transfers/{transfer_uuid}; download the bundle when it succeeds. Bundles expire after TRANSFER_BUNDLE_TTL_HOURS (72 by default).",
        "operationId": "createProjectExport",
        "parameters": [
          {
            "$ref": "#/components/parameters/projectUUID"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "include_events": true
              },
              "schema": {
                "properties": {
                  "from": {
                    "format": "date-time",
                    "type": "string"
                  },
                  "include_events": {
                    "type": "boolean"
                  },
                  "to": {
                    "format": "date-time",
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "transfer": {
                    "bundle_bytes": 0,
                    "bundle_deleted": false,
                    "created_at": "2026-09-13T12:30:45Z",
                    "created_by": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                    "kind": "export",
                    "options": {
                      "include_events": true
                    },
                    "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                    "progress": {
                      "boards": 3,
                      "cohorts": 2,
                      "event_part_rows": 0,
                      "event_parts_done": 0,
                      "events_done": 450000,
                      "events_total": 1200000,
                      "phase": "events",
                      "users_done": 8000,
                      "users_total": 8000
                    },
                    "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                    "started_at": "2026-09-13T12:30:45Z",
                    "status": "running",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "7a9b0c1d-2e3f-4a5b-8c6d-7e8f9a0b1c2d"
                  }
                },
                "schema": {
                  "properties": {
                    "transfer": {
                      "$ref": "#/components/schemas/TransferJob"
                    }
                  },
                  "required": [
                    "transfer"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Export queued"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Caller is not an admin or email unverified"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Project not found in this organization"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          },
          "503": {
            "content": {
              "application/json": {
                "example": {
                  "error": "not ready"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "The organization already has the maximum transfers in progress"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Export a project to a bundle, in the background (admin only)",
        "tags": [
          "transfers"
        ]
      }
    },
    "/v1/projects/{project_uuid}/key/rotate": {
      "post": {
        "description": "Clients using the old key stop ingesting immediately.",
        "operationId": "rotateProjectKey",
        "parameters": [
          {
            "$ref": "#/components/parameters/projectUUID"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "project": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "data_residency": "US",
                    "key": "8a0b6c1d2e3f4a5b6c7d8e9f0a1b2c3d",
                    "name": "Mobile app",
                    "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                    "selected": true,
                    "status_uuid": "9d3f1e2c-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f"
                  }
                },
                "schema": {
                  "properties": {
                    "project": {
                      "$ref": "#/components/schemas/Project"
                    }
                  },
                  "required": [
                    "project"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Project with the new key"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Project not found in this organization"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Issue a new public ingest key (admin only)",
        "tags": [
          "projects"
        ]
      }
    },
    "/v1/projects/{project_uuid}/secret/rotate": {
      "post": {
        "description": "The old secret stops working immediately; the new one is shown once.",
        "operationId": "rotateProjectSecret",
        "parameters": [
          {
            "$ref": "#/components/parameters/projectUUID"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "notice": "store the secret now; it is not shown again",
                  "project": {
                    "created_at": "2026-09-13T12:30:45Z",
                    "data_residency": "US",
                    "key": "3142566d8c88721d6d34bd9443d556bf",
                    "name": "Mobile app",
                    "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                    "secret": "ps_1a2b…",
                    "selected": true,
                    "status_uuid": "9d3f1e2c-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f"
                  }
                },
                "schema": {
                  "properties": {
                    "notice": {
                      "type": "string"
                    },
                    "project": {
                      "$ref": "#/components/schemas/Project"
                    }
                  },
                  "required": [
                    "project",
                    "notice"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Project with the new secret"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Project not found in this organization"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Issue a new project secret (admin only)",
        "tags": [
          "projects"
        ]
      }
    },
    "/v1/projects/{project_uuid}/snippet": {
      "get": {
        "description": "Copy-paste initialization code for the project (Flutter, web or raw HTTP) with the public project key filled in. The project secret never appears in a snippet.",
        "operationId": "getProjectSnippet",
        "parameters": [
          {
            "$ref": "#/components/parameters/projectUUID"
          },
          {
            "in": "query",
            "name": "platform",
            "required": true,
            "schema": {
              "enum": [
                "web",
                "flutter",
                "node",
                "react",
                "nextjs",
                "react-native",
                "python",
                "go",
                "java",
                "android",
                "swift",
                "ruby",
                "php",
                "dotnet",
                "unity",
                "http"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "language": "bash",
                  "note": "The project key only allows writes and is safe to ship in apps. Keep the project secret on your servers, out of version control; snippets never include it.",
                  "platform": "http",
                  "project_key": "3142566d8c88721d6d34bd9443d556bf",
                  "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                  "snippet": "curl -X POST https://api.iforevents.com/v1/events/track -H \"X-Project-Key: 3142566d8c88721d6d34bd9443d556bf\" ..."
                },
                "schema": {
                  "$ref": "#/components/schemas/GetProjectSnippetResponse"
                }
              }
            },
            "description": "Snippet"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Unknown platform"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Project not found in this organization"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "SDK initialization snippet for a platform",
        "tags": [
          "projects"
        ]
      }
    },
    "/v1/setup/status": {
      "get": {
        "description": "Tells the dashboard whether the server still needs its first admin account (`needs_setup`) and whether self-service signup is open under the configured `SIGNUP_MODE` (bootstrap: only the first signup; closed: none; open: anyone). Reveals nothing beyond the fact that no account exists yet.",
        "operationId": "getSetupStatus",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "email_verify": false,
                  "needs_setup": true,
                  "self_hosted": true,
                  "signup_mode": "bootstrap",
                  "signup_open": true
                },
                "schema": {
                  "properties": {
                    "email_verify": {
                      "description": "false when accounts are verified on creation (self-hosted without SMTP)",
                      "type": "boolean"
                    },
                    "needs_setup": {
                      "description": "true until the first account exists on a self-hosted server",
                      "type": "boolean"
                    },
                    "self_hosted": {
                      "type": "boolean"
                    },
                    "signup_mode": {
                      "enum": [
                        "open",
                        "bootstrap",
                        "closed"
                      ],
                      "type": "string"
                    },
                    "signup_open": {
                      "description": "whether POST /v1/auth/register would be accepted right now",
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "self_hosted",
                    "needs_setup",
                    "signup_open",
                    "signup_mode",
                    "email_verify"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Setup state"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [],
        "summary": "First-run state of a self-hosted server",
        "tags": [
          "auth"
        ]
      }
    },
    "/v1/team": {
      "get": {
        "operationId": "listTeamMembers",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "members": [
                    {
                      "created_at": "2026-09-13T12:30:45Z",
                      "email": "ada@example.com",
                      "email_verified": true,
                      "name": "Ada Lovelace",
                      "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                      "role_name": "admin",
                      "role_uuid": "7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
                      "status_uuid": "9d3f1e2c-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                      "updated_at": "2026-09-13T12:30:45Z",
                      "uuid": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f"
                    }
                  ]
                },
                "schema": {
                  "properties": {
                    "members": {
                      "items": {
                        "$ref": "#/components/schemas/SystemUser"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "members"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Members"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List members of the caller's organization",
        "tags": [
          "team"
        ]
      }
    },
    "/v1/team/{user_uuid}": {
      "patch": {
        "operationId": "updateTeamMember",
        "parameters": [
          {
            "in": "path",
            "name": "user_uuid",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "enabled": true,
                "role_name": "admin"
              },
              "schema": {
                "properties": {
                  "enabled": {
                    "description": "false disables the member's login; omit to leave it unchanged.",
                    "type": "boolean"
                  },
                  "role_name": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": "member updated"
                },
                "schema": {
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "message"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Updated"
          },
          "400": {
            "content": {
              "application/json": {
                "example": {
                  "error": "invalid input"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Malformed body"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "403": {
            "content": {
              "application/json": {
                "example": {
                  "error": "insufficient permissions"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Caller is not an admin"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Not a member of this organization"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Change a member's role or enable state (admin only)",
        "tags": [
          "team"
        ]
      }
    },
    "/v1/transfers": {
      "get": {
        "operationId": "listTransfers",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "transfers": [
                    {
                      "bundle_bytes": 0,
                      "bundle_deleted": false,
                      "created_at": "2026-09-13T12:30:45Z",
                      "created_by": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                      "kind": "export",
                      "options": {
                        "include_events": true
                      },
                      "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                      "progress": {
                        "boards": 3,
                        "cohorts": 2,
                        "event_part_rows": 0,
                        "event_parts_done": 0,
                        "events_done": 450000,
                        "events_total": 1200000,
                        "phase": "events",
                        "users_done": 8000,
                        "users_total": 8000
                      },
                      "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                      "started_at": "2026-09-13T12:30:45Z",
                      "status": "running",
                      "updated_at": "2026-09-13T12:30:45Z",
                      "uuid": "7a9b0c1d-2e3f-4a5b-8c6d-7e8f9a0b1c2d"
                    }
                  ]
                },
                "schema": {
                  "properties": {
                    "transfers": {
                      "items": {
                        "$ref": "#/components/schemas/TransferJob"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "transfers"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Newest first"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "The organization's latest exports and imports (admin only)",
        "tags": [
          "transfers"
        ]
      }
    },
    "/v1/transfers/{transfer_uuid}": {
      "get": {
        "operationId": "getTransfer",
        "parameters": [
          {
            "in": "path",
            "name": "transfer_uuid",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "transfer": {
                    "bundle_bytes": 0,
                    "bundle_deleted": false,
                    "created_at": "2026-09-13T12:30:45Z",
                    "created_by": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                    "kind": "export",
                    "options": {
                      "include_events": true
                    },
                    "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                    "progress": {
                      "boards": 3,
                      "cohorts": 2,
                      "event_part_rows": 0,
                      "event_parts_done": 0,
                      "events_done": 450000,
                      "events_total": 1200000,
                      "phase": "events",
                      "users_done": 8000,
                      "users_total": 8000
                    },
                    "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                    "started_at": "2026-09-13T12:30:45Z",
                    "status": "running",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "7a9b0c1d-2e3f-4a5b-8c6d-7e8f9a0b1c2d"
                  }
                },
                "schema": {
                  "properties": {
                    "transfer": {
                      "$ref": "#/components/schemas/TransferJob"
                    }
                  },
                  "required": [
                    "transfer"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Transfer"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No such transfer in this organization"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One export or import with its progress (admin only)",
        "tags": [
          "transfers"
        ]
      }
    },
    "/v1/transfers/{transfer_uuid}/bundle": {
      "get": {
        "description": "Range requests are honored, so an interrupted download resumes. X-Bundle-SHA256 carries the file's digest.",
        "operationId": "downloadTransferBundle",
        "parameters": [
          {
            "in": "path",
            "name": "transfer_uuid",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/x-tar": {
                "example": "<bundle bytes>",
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              }
            },
            "description": "The bundle (a tar of gzipped NDJSON parts)"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No such export, or its bundle expired"
          },
          "409": {
            "content": {
              "application/json": {
                "example": {
                  "error": "already exists"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "The export has not finished"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Download a finished export's bundle (admin only)",
        "tags": [
          "transfers"
        ]
      }
    },
    "/v1/transfers/{transfer_uuid}/cancel": {
      "post": {
        "description": "An import keeps the chunks it already stored.",
        "operationId": "cancelTransfer",
        "parameters": [
          {
            "in": "path",
            "name": "transfer_uuid",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "transfer": {
                    "bundle_bytes": 0,
                    "bundle_deleted": false,
                    "created_at": "2026-09-13T12:30:45Z",
                    "created_by": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                    "kind": "export",
                    "options": {
                      "include_events": true
                    },
                    "organization_uuid": "0b7e2b1a-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
                    "progress": {
                      "boards": 3,
                      "cohorts": 2,
                      "event_part_rows": 0,
                      "event_parts_done": 0,
                      "events_done": 450000,
                      "events_total": 1200000,
                      "phase": "events",
                      "users_done": 8000,
                      "users_total": 8000
                    },
                    "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                    "started_at": "2026-09-13T12:30:45Z",
                    "status": "running",
                    "updated_at": "2026-09-13T12:30:45Z",
                    "uuid": "7a9b0c1d-2e3f-4a5b-8c6d-7e8f9a0b1c2d"
                  }
                },
                "schema": {
                  "properties": {
                    "transfer": {
                      "$ref": "#/components/schemas/TransferJob"
                    }
                  },
                  "required": [
                    "transfer"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Stopping"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "project not found"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "No such transfer in this organization"
          },
          "409": {
            "content": {
              "application/json": {
                "example": {
                  "error": "already exists"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Already finished"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Stop a queued or running transfer (admin only)",
        "tags": [
          "transfers"
        ]
      }
    },
    "/v1/usage/storage": {
      "get": {
        "description": "The free plan keeps at most budget_bytes logical bytes of events per project: the uncompressed size of the stored rows' values (47 bytes of fixed-size columns plus every stored string: name, property keys and values, page, URL parts, referrer, title), counted over the rows the retention window still keeps. It is not the compressed size on disk. Each total is ingest's running count, set again from ClickHouse every reconcile_interval_seconds and after an erasure or an import. At warning_percent the dashboard warns; once a project's total reaches the budget its ingest answers 402 storage_budget_exceeded and nothing already stored is touched. Paid plans and self-hosted installs have no budget: limited is false and projects is empty. See docs/STORAGE_BUDGET.md.",
        "operationId": "getStorageUsage",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "budget_bytes": 700000000,
                  "limited": true,
                  "measure": "logical_row_bytes",
                  "plan_code": "free",
                  "projects": [
                    {
                      "name": "Storefront",
                      "percent": 83.250112,
                      "project_uuid": "5f1c2e7a-1c2d-4b3e-9f10-1a2b3c4d5e6f",
                      "reconciled_at": "2026-09-13T12:30:45Z",
                      "state": "warning",
                      "used_bytes": 83250112
                    }
                  ],
                  "reconcile_interval_seconds": 3600,
                  "warning_percent": 80
                },
                "schema": {
                  "$ref": "#/components/schemas/StorageUsageReport"
                }
              }
            },
            "description": "Budget and per-project use"
          },
          "401": {
            "content": {
              "application/json": {
                "example": {
                  "error": "authentication required"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Missing or invalid credentials"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": "rate limit exceeded"
                },
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Rate limit exceeded (Retry-After header set)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "The free plan's stored-bytes budget and each project's use of it",
        "tags": [
          "projects"
        ]
      }
    }
  },
  "servers": [
    {
      "description": "Production",
      "url": "https://api.iforevents.com"
    },
    {
      "description": "Self-hosted deployment",
      "url": "{scheme}://{host}",
      "variables": {
        "host": {
          "default": "api.example.com"
        },
        "scheme": {
          "default": "https",
          "enum": [
            "https",
            "http"
          ]
        }
      }
    },
    {
      "description": "Local (go run ./cmd)",
      "url": "http://127.0.0.1:8000"
    }
  ],
  "tags": [
    {
      "description": "Liveness and readiness probes.",
      "name": "health"
    },
    {
      "description": "Legacy session endpoints of the data plane; new signups and logins go through the accounts service.",
      "name": "auth"
    },
    {
      "description": "Members of the caller's organization.",
      "name": "team"
    },
    {
      "description": "Projects, their public keys, their once-shown secrets and SDK snippets.",
      "name": "projects"
    },
    {
      "description": "Event ingestion with the public project key (X-Project-Key).",
      "name": "ingest"
    },
    {
      "description": "Analytics over a project's events. Every route accepts a session or, for programmatic access, the project key and secret (read-only, pinned to that project).",
      "name": "analytics"
    },
    {
      "description": "GDPR subject access and erasure.",
      "name": "privacy"
    },
    {
      "description": "Saved dashboards of widgets. Session callers only: any role reads, any role but viewer writes.",
      "name": "boards"
    }
  ],
  "x-tagGroups": [
    {
      "name": "Core",
      "tags": [
        "health",
        "auth",
        "projects",
        "team"
      ]
    },
    {
      "name": "Ingest",
      "tags": [
        "ingest"
      ]
    },
    {
      "name": "Analytics",
      "tags": [
        "analytics",
        "boards"
      ]
    },
    {
      "name": "Privacy",
      "tags": [
        "privacy"
      ]
    }
  ]
}
