{
  "openapi": "3.1.0",
  "info": {
    "title": "Antlytics API",
    "version": "1.1.0",
    "description": "Public JSON API for Antlytics web analytics — read stats, manage sites/goals/funnels, and query custom events. Privacy-first analytics for developers. Requires a paid plan (Starter or Pro, including trial). Base URL: https://www.antlytics.com/api/v1",
    "contact": {
      "name": "Antlytics support",
      "url": "https://www.antlytics.com/contact",
      "email": "support@antlytics.com"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://www.antlytics.com/api/v1",
      "description": "Production"
    }
  ],
  "security": [{ "bearerAuth": [] }],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "ant_<token>",
        "description": "API token from Settings → API tokens. Header: Authorization: Bearer ant_..."
      }
    },
    "parameters": {
      "site_id": {
        "name": "site_id",
        "in": "query",
        "required": true,
        "schema": { "type": "string", "format": "uuid" },
        "description": "UUID of the Antlytics site"
      },
      "from": {
        "name": "from",
        "in": "query",
        "required": false,
        "schema": { "type": "string", "format": "date-time" },
        "description": "ISO 8601 start datetime (inclusive)"
      },
      "to": {
        "name": "to",
        "in": "query",
        "required": false,
        "schema": { "type": "string", "format": "date-time" },
        "description": "ISO 8601 end datetime (exclusive)"
      },
      "limit10": {
        "name": "limit",
        "in": "query",
        "required": false,
        "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 10 },
        "description": "Max results (1–100)"
      },
      "limit20": {
        "name": "limit",
        "in": "query",
        "required": false,
        "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 },
        "description": "Max results (1–100)"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": { "type": "string" }
        }
      },
      "Stats": {
        "type": "object",
        "properties": {
          "visitors": { "type": "integer" },
          "pageviews": { "type": "integer" },
          "bounce_rate": { "type": "number" },
          "sessions": { "type": "integer" }
        }
      },
      "PageRow": {
        "type": "object",
        "properties": {
          "path": { "type": "string" },
          "pageviews": { "type": "integer" },
          "visitors": { "type": "integer" }
        }
      },
      "ReferrerRow": {
        "type": "object",
        "properties": {
          "referrer": { "type": "string" },
          "visits": { "type": "integer" }
        }
      },
      "UtmRow": {
        "type": "object",
        "properties": {
          "utm_source": { "type": "string", "nullable": true },
          "utm_medium": { "type": "string", "nullable": true },
          "utm_campaign": { "type": "string", "nullable": true },
          "visitors": { "type": "integer" },
          "pageviews": { "type": "integer" }
        }
      },
      "CountryRow": {
        "type": "object",
        "properties": {
          "country": { "type": "string", "description": "ISO 3166-1 alpha-2" },
          "visitors": { "type": "integer" },
          "pageviews": { "type": "integer" }
        }
      },
      "DeviceRow": {
        "type": "object",
        "properties": {
          "device": { "type": "string", "enum": ["desktop", "mobile", "tablet"] },
          "visitors": { "type": "integer" },
          "pageviews": { "type": "integer" }
        }
      },
      "Site": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "url": { "type": "string" },
          "tracking_id": { "type": "string", "format": "uuid" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "Goal": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "site_id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "path_pattern": { "type": "string" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "FunnelStep": {
        "type": "object",
        "required": ["type", "value"],
        "properties": {
          "type": { "type": "string", "enum": ["path", "event"] },
          "value": { "type": "string" }
        }
      },
      "Funnel": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "site_id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "steps": { "type": "array", "items": { "$ref": "#/components/schemas/FunnelStep" } },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "FunnelResults": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "site_id": { "type": "string", "format": "uuid" },
          "period": {
            "type": "object",
            "properties": {
              "from": { "type": "string", "format": "date-time" },
              "to": { "type": "string", "format": "date-time" }
            }
          },
          "result": {
            "type": "object",
            "properties": {
              "overallConversion": { "type": "number" },
              "steps": { "type": "array", "items": { "type": "object" } }
            }
          }
        }
      },
      "EventRow": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "events": { "type": "integer" },
          "sessions": { "type": "integer" }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid token",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "Forbidden": {
        "description": "Free plan — API requires a paid plan",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "NotFound": {
        "description": "Site not found or not owned by this token",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "Unprocessable": {
        "description": "Invalid query parameters",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "TooManyRequests": {
        "description": "Rate limit exceeded (60 req/min per token)",
        "headers": {
          "Retry-After": {
            "schema": { "type": "integer" },
            "description": "Seconds to wait before retrying"
          }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      }
    }
  },
  "paths": {
    "/stats": {
      "get": {
        "operationId": "getStats",
        "summary": "Site summary statistics",
        "description": "Visitors, pageviews, bounce rate, and sessions for a site over a time range.",
        "parameters": [
          { "$ref": "#/components/parameters/site_id" },
          { "$ref": "#/components/parameters/from" },
          { "$ref": "#/components/parameters/to" }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Stats" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/Unprocessable" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/pages": {
      "get": {
        "operationId": "getPages",
        "summary": "Top pages",
        "description": "Top pages by pageviews for a site.",
        "parameters": [
          { "$ref": "#/components/parameters/site_id" },
          { "$ref": "#/components/parameters/from" },
          { "$ref": "#/components/parameters/to" },
          { "$ref": "#/components/parameters/limit10" }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/PageRow" }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/Unprocessable" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/referrers": {
      "get": {
        "operationId": "getReferrers",
        "summary": "Top referrers",
        "description": "Top referrers by visit count for a site.",
        "parameters": [
          { "$ref": "#/components/parameters/site_id" },
          { "$ref": "#/components/parameters/from" },
          { "$ref": "#/components/parameters/to" },
          { "$ref": "#/components/parameters/limit10" }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/ReferrerRow" }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/Unprocessable" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/utm": {
      "get": {
        "operationId": "getUtm",
        "summary": "UTM breakdown",
        "description": "UTM source, medium, and campaign breakdown. Only events with a utm_source are included.",
        "parameters": [
          { "$ref": "#/components/parameters/site_id" },
          { "$ref": "#/components/parameters/from" },
          { "$ref": "#/components/parameters/to" },
          { "$ref": "#/components/parameters/limit20" }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/UtmRow" }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/Unprocessable" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/countries": {
      "get": {
        "operationId": "getCountries",
        "summary": "Countries breakdown",
        "description": "Visitors and pageviews by country (ISO 3166-1 alpha-2).",
        "parameters": [
          { "$ref": "#/components/parameters/site_id" },
          { "$ref": "#/components/parameters/from" },
          { "$ref": "#/components/parameters/to" },
          { "$ref": "#/components/parameters/limit20" }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/CountryRow" }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/Unprocessable" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/devices": {
      "get": {
        "operationId": "getDevices",
        "summary": "Devices breakdown",
        "description": "Visitors and pageviews by device type (desktop, mobile, tablet).",
        "parameters": [
          { "$ref": "#/components/parameters/site_id" },
          { "$ref": "#/components/parameters/from" },
          { "$ref": "#/components/parameters/to" },
          { "$ref": "#/components/parameters/limit20" }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/DeviceRow" }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/Unprocessable" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/sites": {
      "get": {
        "operationId": "listSites",
        "summary": "List sites",
        "description": "List all analytics sites owned by the API token user.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/Site" }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      },
      "post": {
        "operationId": "createSite",
        "summary": "Create site",
        "description": "Create a new analytics site. Free accounts are limited to one site.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name", "url"],
                "properties": {
                  "name": { "type": "string", "maxLength": 100 },
                  "url": { "type": "string", "description": "Public site URL" }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Site" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "422": { "$ref": "#/components/responses/Unprocessable" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/goals": {
      "get": {
        "operationId": "listGoals",
        "summary": "List conversion goals",
        "parameters": [{ "$ref": "#/components/parameters/site_id" }],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/Goal" }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/Unprocessable" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      },
      "post": {
        "operationId": "createGoal",
        "summary": "Create conversion goal",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["site_id", "name", "path_pattern"],
                "properties": {
                  "site_id": { "type": "string", "format": "uuid" },
                  "name": { "type": "string", "maxLength": 100 },
                  "path_pattern": {
                    "type": "string",
                    "description": "Exact pathname to count as a conversion (must start with /)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Goal" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/Unprocessable" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/funnels": {
      "get": {
        "operationId": "listFunnels",
        "summary": "List funnels",
        "parameters": [{ "$ref": "#/components/parameters/site_id" }],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/Funnel" }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/Unprocessable" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      },
      "post": {
        "operationId": "createFunnel",
        "summary": "Create funnel",
        "description": "Create a conversion funnel with 2–8 ordered path or event steps.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["site_id", "name", "steps"],
                "properties": {
                  "site_id": { "type": "string", "format": "uuid" },
                  "name": { "type": "string", "maxLength": 100 },
                  "steps": {
                    "type": "array",
                    "minItems": 2,
                    "maxItems": 8,
                    "items": { "$ref": "#/components/schemas/FunnelStep" }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Funnel" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/Unprocessable" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/funnels/{id}/results": {
      "get": {
        "operationId": "getFunnelResults",
        "summary": "Funnel step results",
        "description": "Compute ordered step progression for a funnel. Defaults to the last 7 days when from/to are omitted.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          },
          { "$ref": "#/components/parameters/from" },
          { "$ref": "#/components/parameters/to" }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/FunnelResults" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/Unprocessable" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    },
    "/events": {
      "get": {
        "operationId": "getEvents",
        "summary": "Custom events breakdown",
        "description": "Custom event counts grouped by event name.",
        "parameters": [
          { "$ref": "#/components/parameters/site_id" },
          { "$ref": "#/components/parameters/from" },
          { "$ref": "#/components/parameters/to" },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/EventRow" }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/Unprocessable" },
          "429": { "$ref": "#/components/responses/TooManyRequests" }
        }
      }
    }
  }
}
