{"swagger": "2.0", "info": {"title": "Respectlytics API", "description": "Privacy-first mobile analytics API.\n\n## Getting Started\n\n1. [Create an account](/register/) and set up your first app\n2. Copy your **App API Key** (UUID) from the [Dashboard](/dashboard/)\n3. Integrate with our [SDKs](/sdk/) or call the API directly\n\n## Authentication\n\nAll API endpoints require the `X-App-Key` header with your App API Key:\n\n```\nX-App-Key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n```\n\n## Core Endpoints\n\n- **POST /api/v1/events/** — Submit analytics events\n- **GET /api/v1/events/summary/** — Retrieve event summary\n- **GET /api/v1/events/top/** — Top events by count\n\n## SDKs\n\nOfficial SDKs handle authentication, batching, and RAM-only event queue automatically:\n- [Swift (iOS)](/sdk/swift/)\n- [Kotlin (Android)](/sdk/kotlin/)\n- [Flutter](/sdk/flutter/)\n- [React Native](/sdk/react-native/)\n\n## Support\n\nQuestions? Visit our [SDK documentation](/sdk/) or [contact us](/contact/).\n", "license": {"name": "Proprietary"}, "version": "v1"}, "host": "respectlytics.com", "schemes": ["https"], "basePath": "/api", "consumes": ["application/json"], "produces": ["application/json"], "securityDefinitions": {"App API Key": {"type": "apiKey", "name": "X-App-Key", "in": "header", "description": "App API Key sent via the X-App-Key header.\n\n• In Swagger UI: click the Authorize button and paste only the UUID value.\n• In your app or curl: send header X-App-Key: App_API_Key.\n\n"}}, "security": [{"App API Key": []}], "paths": {"/v1/": {"get": {"operationId": "v1_list", "summary": "Respectlytics API Root", "description": "Welcome to the Respectlytics API - a privacy-first mobile analytics platform.\n\n> ⚠️ **AUTHENTICATION REQUIRED:** All endpoints require app_key authentication.\n\n**Mobile App API Endpoints:**\n- POST /api/v1/events/ - Submit an analytics event\n- GET /api/v1/events/summary/ - Get aggregated analytics data\n- GET /api/v1/events/geo-summary/ - Get geographic distribution\n- GET /api/v1/events/funnel/ - Analyze conversion funnels\n- GET /api/v1/events/event-types/ - List all event types for your app\n\n**Getting Started:**\n1. Register at /register/ and login at /login/\n2. Create an app via the Dashboard at /dashboard/\n3. Copy your app_key and use it in your mobile app\n4. Send events from your app using the X-App-Key header", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["v1"]}, "parameters": []}, "/v1/analytics/conversion-paths/": {"get": {"operationId": "v1_analytics_conversion-paths_list", "summary": "Discover top conversion paths", "description": "\nAutomatically discover the most common behavior sequences that lead to conversion within sessions.\n\n**Required Parameter:**\n- `conversion_events`: Comma-separated event names (e.g., \"purchase,subscription_start\")\n\n**What This Endpoint Does:**\n1. Finds all sessions that include a conversion event\n2. Extracts the event sequence leading to conversion within each session\n3. Groups common patterns and ranks by frequency\n4. Returns top N paths with timing statistics\n\n**Session-Based Analysis:**\n- Each session is analyzed independently (no cross-session tracking)\n- Paths show what happens within a single app usage period\n- Maximum session duration is ~2 hours\n\n**Use Cases:**\n- Discover which in-session journeys lead to purchase\n- Find the most effective onboarding flows\n- Identify hidden conversion patterns within sessions\n", "parameters": [{"name": "conversion_events", "in": "query", "description": "REQUIRED: Comma-separated event names to count as conversions", "required": true, "type": "string"}, {"name": "limit", "in": "query", "description": "Maximum number of paths to return (default: 5, max: 20)", "required": false, "type": "integer"}, {"name": "min_sessions", "in": "query", "description": "Minimum sessions for a path to be included (default: 3)", "required": false, "type": "integer"}, {"name": "max_path_length", "in": "query", "description": "Maximum events in a path before conversion (default: 10)", "required": false, "type": "integer"}, {"name": "start_date", "in": "query", "description": "Start date filter (YYYY-MM-DD)", "required": false, "type": "string", "format": "date"}, {"name": "end_date", "in": "query", "description": "End date filter (YYYY-MM-DD)", "required": false, "type": "string", "format": "date"}, {"name": "tz", "in": "query", "description": "IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Dates are interpreted in this timezone. Defaults to UTC.", "required": false, "type": "string", "default": "UTC"}], "responses": {"200": {"description": "Top conversion paths with statistics", "examples": {"application/json": {"app": {"id": 1, "name": "My App", "slug": "my-app"}, "filters": {"conversion_events": ["purchase"], "start_date": null, "end_date": null, "limit": 5, "min_sessions": 3, "max_path_length": 10}, "data_quality": {"total_converting_sessions": 234, "paths_analyzed": 187, "unique_paths_found": 42}, "top_conversion_paths": [{"rank": 1, "path": ["app_open", "feature_demo", "pricing_view", "purchase"], "sessions": 89, "conversion_rate": 0.42, "avg_duration_minutes": 15.5, "step_timings": [{"from": "app_open", "to": "feature_demo", "avg_minutes": 2.3}, {"from": "feature_demo", "to": "pricing_view", "avg_minutes": 8.1}, {"from": "pricing_view", "to": "purchase", "avg_minutes": 5.1}]}], "interpretation": "These paths show what sessions do before they convert. Each session is analyzed independently."}}}, "400": {"description": "Missing or invalid parameters"}, "401": {"description": "Unauthorized - missing or invalid app_key"}}, "tags": ["Analytics"]}, "parameters": []}, "/v1/analytics/conversions/": {"get": {"operationId": "v1_analytics_conversions_list", "description": "\nGet conversion summary with flexible time granularity.\n\n**Required Parameter:**\nThe `conversion_events` parameter is **required**. Specify which events to count as conversions.\n\n**Example:**\n`?conversion_events=purchase,subscription_complete`\n\n**What is a \"conversion rate\"?**\nConversion rate = sessions with conversions / total unique sessions per period.\nA session is a unique app usage period (max 2 hours), identified by session_id.\n\n**Granularity Options:**\n- `day` (default): Daily conversion data\n- `week`: Weekly conversions - ISO weeks, Mon-Sun\n- `month`: Monthly conversions\n- `quarter`: Quarterly conversions\n- `year`: Yearly conversions\n\n**Period Labels:**\n| Granularity | Format | Example |\n|-------------|--------|---------|\n| day | YYYY-MM-DD | 2025-11-27 |\n| week | YYYY-Www | 2025-W48 |\n| month | YYYY-MM | 2025-11 |\n| quarter | YYYY-Qn | 2025-Q4 |\n| year | YYYY | 2025 |\n", "parameters": [{"name": "X-App-Key", "in": "header", "description": "App Key for authentication", "required": true, "type": "string"}, {"name": "conversion_events", "in": "query", "description": "REQUIRED: Comma-separated event names to count as conversions (e.g., purchase,subscription_complete)", "required": true, "type": "string"}, {"name": "from", "in": "query", "description": "Start date in YYYY-MM-DD format", "required": false, "type": "string"}, {"name": "to", "in": "query", "description": "End date in YYYY-MM-DD format", "required": false, "type": "string"}, {"name": "tz", "in": "query", "description": "IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Dates are interpreted in this timezone. Defaults to UTC.", "required": false, "type": "string", "default": "UTC"}, {"name": "granularity", "in": "query", "description": "Time period grouping: day (default), week, month, quarter, year", "required": false, "type": "string", "enum": ["day", "week", "month", "quarter", "year"]}], "responses": {"200": {"description": "Conversion summary data by period", "examples": {"application/json": {"app_name": "My App", "granularity": "month", "conversion_events": ["purchase", "subscription_start"], "date_range": {"from": "2025-09-01", "to": "2025-11-27"}, "summary": {"total_conversions": 1042, "avg_conversion_rate": 0.0312}, "conversions": [{"period": "2025-11", "conversions": 342, "active_sessions": 11793, "conversion_rate": 0.029}, {"period": "2025-10", "conversions": 385, "active_sessions": 12419, "conversion_rate": 0.031}, {"period": "2025-09", "conversions": 315, "active_sessions": 9265, "conversion_rate": 0.034}], "interpretation": "Conversion rate shows the percentage of sessions that include a conversion event. Each session is analyzed independently."}}}, "400": {"description": "Bad Request - missing conversion_events or invalid parameters", "examples": {"application/json": {"error": "conversion_events parameter required", "detail": "Please specify which events to count as conversions.", "your_event_types": ["app_open", "screen_view", "button_click", "checkout_start", "payment_success"], "example": "?conversion_events=payment_success,checkout_start"}}}, "401": {"description": "Unauthorized - missing or invalid app_key"}}, "tags": ["v1"]}, "parameters": []}, "/v1/analytics/dau/": {"get": {"operationId": "v1_analytics_dau_list", "description": "\nGet active sessions with flexible time granularity.\n\n**What is a \"session\"?**\nA session represents a single app usage period, identified by a unique session_id.\nSessions automatically rotate every 2 hours and do not persist across app restarts.\nThis provides usage metrics without requiring user consent for tracking.\n\n**Granularity Options:**\n- `day` (default): Daily active sessions\n- `week`: Weekly active sessions - ISO weeks, Mon-Sun\n- `month`: Monthly active sessions\n- `quarter`: Quarterly active sessions\n- `year`: Yearly active sessions\n\n**Period Labels:**\n| Granularity | Format | Example |\n|-------------|--------|---------|\n| day | YYYY-MM-DD | 2025-11-27 |\n| week | YYYY-Www | 2025-W48 |\n| month | YYYY-MM | 2025-11 |\n| quarter | YYYY-Qn | 2025-Q4 |\n| year | YYYY | 2025 |\n", "parameters": [{"name": "X-App-Key", "in": "header", "description": "App Key for authentication", "required": true, "type": "string"}, {"name": "from", "in": "query", "description": "Start date in YYYY-MM-DD format", "required": false, "type": "string"}, {"name": "to", "in": "query", "description": "End date in YYYY-MM-DD format", "required": false, "type": "string"}, {"name": "tz", "in": "query", "description": "IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Dates are interpreted in this timezone. Defaults to UTC.", "required": false, "type": "string", "default": "UTC"}, {"name": "granularity", "in": "query", "description": "Time period grouping: day (default), week, month, quarter, year", "required": false, "type": "string", "enum": ["day", "week", "month", "quarter", "year"]}], "responses": {"200": {"description": "Active sessions data by period with session length metrics", "examples": {"application/json": {"app_name": "My App", "granularity": "week", "date_range": {"from": "2025-11-01", "to": "2025-11-27"}, "active_sessions": [{"period": "2025-W48", "unique_sessions": 3456, "total_events": 15234, "avg_session_length_seconds": 245.3, "sessions_with_duration": 2891}, {"period": "2025-W47", "unique_sessions": 3189, "total_events": 14102, "avg_session_length_seconds": 238.7, "sessions_with_duration": 2654}, {"period": "2025-W46", "unique_sessions": 2987, "total_events": 13456, "avg_session_length_seconds": 251.2, "sessions_with_duration": 2503}], "summary": {"total_sessions": 9632, "sessions_with_duration": 8048, "avg_session_length_seconds": 245.1}, "top_events_current_period": [{"event_name": "app_open", "count": 5341}, {"event_name": "screen_view", "count": 4876}]}}}, "400": {"description": "Bad Request - invalid date format or granularity", "examples": {"application/json": {"error": "Invalid granularity. Must be one of: day, week, month, quarter, year"}}}, "401": {"description": "Unauthorized - missing or invalid app_key"}}, "tags": ["v1"]}, "parameters": []}, "/v1/analytics/drop-off/": {"get": {"operationId": "v1_analytics_drop-off_list", "summary": "Get drop-off diagnostics", "description": "\nIdentify where non-converting sessions end.\n\n**Required Parameter:**\n- `conversion_events`: Comma-separated event names (e.g., \"purchase,subscription_start\")\n\n**What This Endpoint Does:**\n1. Finds all sessions that did NOT include a conversion event\n2. Identifies their \"last event before session end\" (where they dropped off)\n3. Ranks events by drop-off frequency\n4. Compares non-converting vs converting session behavior patterns\n5. Calculates impact scores to prioritize fixes\n\n**Session-Based Analysis:**\n- Each session is analyzed independently (no cross-session tracking)\n- Shows where sessions end without converting\n- Maximum session duration is ~2 hours\n\n**Use Cases:**\n- Find which features are causing sessions to end without converting\n- Identify friction points in the onboarding flow\n- Prioritize UX improvements for conversion impact\n- Compare where converting vs non-converting sessions spend time\n", "parameters": [{"name": "conversion_events", "in": "query", "description": "REQUIRED: Comma-separated event names to count as conversions", "required": true, "type": "string"}, {"name": "min_sessions", "in": "query", "description": "Minimum sessions for a drop-off point to be included (default: 5)", "required": false, "type": "integer"}, {"name": "limit", "in": "query", "description": "Maximum number of drop-off points to return (default: 10, max: 50)", "required": false, "type": "integer"}, {"name": "start_date", "in": "query", "description": "Start date filter (YYYY-MM-DD)", "required": false, "type": "string", "format": "date"}, {"name": "end_date", "in": "query", "description": "End date filter (YYYY-MM-DD)", "required": false, "type": "string", "format": "date"}, {"name": "tz", "in": "query", "description": "IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Dates are interpreted in this timezone. Defaults to UTC.", "required": false, "type": "string", "default": "UTC"}], "responses": {"200": {"description": "Drop-off diagnostics with ranked problem areas", "examples": {"application/json": {"app": {"id": 1, "name": "My App", "slug": "my-app"}, "filters": {"conversion_events": ["purchase"], "start_date": null, "end_date": null, "min_sessions": 5, "limit": 10}, "data_quality": {"total_sessions": 500, "converting_sessions": 150, "non_converting_sessions": 350, "conversion_rate": 0.3}, "drop_off_points": [{"rank": 1, "event": "pricing_view", "sessions_dropped": 89, "drop_off_rate": 0.25, "avg_time_before_exit_minutes": 2.5, "impact_score": 0.85, "converter_comparison": {"converters_with_event": 120, "converters_event_rate": 0.8, "non_converters_event_rate": 0.45, "differential": -0.35}}], "events_more_common_in_non_converters": [{"event": "support_contact", "non_converter_rate": 0.35, "converter_rate": 0.08, "differential": 0.27}], "interpretation": "Sessions that don't convert - where do they end? Each session is analyzed independently."}}}, "400": {"description": "Missing or invalid parameters"}, "401": {"description": "Unauthorized - missing or invalid app_key"}}, "tags": ["Analytics"]}, "parameters": []}, "/v1/analytics/event-correlation/": {"get": {"operationId": "v1_analytics_event-correlation_list", "summary": "Get event correlation analysis (Conversion Drivers)", "description": "\nIdentify which events correlate with conversion (positive or negative lift).\n\n**Required Parameter:**\n- `conversion_events`: Comma-separated event names (e.g., \"purchase,subscription_start\")\n\n**What This Endpoint Does:**\n1. For each event type, calculates conversion rate of sessions that include it vs don't\n2. Computes lift score: `(rate_with / rate_without - 1) × 100`\n3. Separates events into positive correlation (boost conversion) and negative correlation (hurt conversion)\n4. Ranks by absolute lift value\n\n**Lift Score Interpretation:**\n- `+245%` means sessions with this event are 3.45x more likely to convert\n- `-67%` means sessions with this event are 67% less likely to convert\n- `0%` means no correlation with conversion\n\n**Session-Based Analysis:**\n- Each session is analyzed independently (no cross-session tracking)\n- Minimum 10 sessions per event by default (configurable)\n- Maximum session duration is ~2 hours\n\n**Use Cases:**\n- Find which in-session behaviors drive conversions\n- Identify features that correlate with session abandonment\n- Prioritize feature development based on conversion impact\n- A/B test validation: does new feature improve conversion?\n", "parameters": [{"name": "conversion_events", "in": "query", "description": "REQUIRED: Comma-separated event names to count as conversions", "required": true, "type": "string"}, {"name": "min_sessions", "in": "query", "description": "Minimum sessions for an event to be included (default: 10)", "required": false, "type": "integer"}, {"name": "limit", "in": "query", "description": "Maximum events per category (default: 10, max: 50)", "required": false, "type": "integer"}, {"name": "start_date", "in": "query", "description": "Start date filter (YYYY-MM-DD)", "required": false, "type": "string", "format": "date"}, {"name": "end_date", "in": "query", "description": "End date filter (YYYY-MM-DD)", "required": false, "type": "string", "format": "date"}, {"name": "tz", "in": "query", "description": "IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Dates are interpreted in this timezone. Defaults to UTC.", "required": false, "type": "string", "default": "UTC"}], "responses": {"200": {"description": "Event correlation analysis with lift scores", "examples": {"application/json": {"app": {"id": 1, "name": "My App", "slug": "my-app"}, "filters": {"conversion_events": ["purchase"], "start_date": null, "end_date": null, "min_sessions": 10, "limit": 10}, "data_quality": {"total_sessions": 500, "converting_sessions": 150, "non_converting_sessions": 350, "baseline_conversion_rate": 0.3, "events_analyzed": 15}, "positive_correlations": [{"rank": 1, "event": "feature_demo", "lift_percent": 245.5, "sessions_with_event": 456, "sessions_without_event": 44, "conversion_rate_with": 0.52, "conversion_rate_without": 0.15, "converts_with": 237, "converts_without": 7}], "negative_correlations": [{"rank": 1, "event": "error_screen", "lift_percent": -67.3, "sessions_with_event": 123, "sessions_without_event": 377, "conversion_rate_with": 0.11, "conversion_rate_without": 0.34, "converts_with": 14, "converts_without": 128}], "neutral_events": ["app_open", "screen_view"], "interpretation": "Sessions that include X: correlation with conversion. Each session analyzed independently."}}}, "400": {"description": "Missing or invalid parameters"}, "401": {"description": "Unauthorized - missing or invalid app_key"}}, "tags": ["Analytics"]}, "parameters": []}, "/v1/analytics/globe-stats/": {"get": {"operationId": "v1_analytics_globe-stats_list", "description": "\nGet country-level analytics optimized for globe visualizations.\n\nThis endpoint provides aggregated statistics by country without period grouping,\nmaking it significantly faster than segment-comparison for geographic data.\nResults are cached for 15 minutes for optimal performance.\n", "parameters": [{"name": "app_key", "in": "query", "description": "Your application's API key (required)", "required": true, "type": "string"}, {"name": "from", "in": "query", "description": "Start date in YYYY-MM-DD format (required)", "required": true, "type": "string", "format": "date"}, {"name": "to", "in": "query", "description": "End date in YYYY-MM-DD format (required)", "required": true, "type": "string", "format": "date"}, {"name": "tz", "in": "query", "description": "IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Dates are interpreted in this timezone. Defaults to UTC.", "required": false, "type": "string", "default": "UTC"}, {"name": "conversion_events", "in": "query", "description": "Comma-separated list of event names to count as conversions (optional)", "required": false, "type": "string"}], "responses": {"200": {"description": "Country-level statistics", "examples": {"application/json": {"data": [{"country": "US", "events": 1234, "sessions": 567, "conversions": 89, "conversion_rate": 15.7}, {"country": "GB", "events": 890, "sessions": 345, "conversions": 45, "conversion_rate": 13.0}], "cached": true, "cache_expires_in": 900}}}, "400": {"description": "Bad request - missing or invalid parameters"}, "401": {"description": "Unauthorized - invalid or missing API key"}, "500": {"description": "Internal server error"}}, "tags": ["v1"]}, "parameters": []}, "/v1/analytics/segments/": {"get": {"operationId": "v1_analytics_segments_list", "summary": "Segment Comparison", "description": "\nCompare conversion rates across different session segments with flexible time granularity.\n\n**Session-Based Analysis:**\nAll analysis is session-scoped. Each unique session_id is counted once per period.\nThis provides privacy-friendly analytics without cross-session tracking.\n\n**Segment Types:**\n- `platform`: Compare iOS, Android, Web, and Other platforms\n- `country`: Compare by ISO 2-letter country code (US, GB, DE, etc.)\n- `depth`: Compare by session depth (events per session) - buckets: 1, 2, 3, 4, 5, 6-10, 11-20, 21+\n- `hour`: Compare by hour of day (0-23 UTC) - ideal for identifying peak engagement times\n\n**Granularity Options:**\n- `day` (default): Daily segment data\n- `week`: Weekly segment data - ISO weeks, Mon-Sun\n- `month`: Monthly segment data\n- `quarter`: Quarterly segment data\n- `year`: Yearly segment data\n\n**Period Labels:**\n| Granularity | Format | Example |\n|-------------|--------|---------|\n| day | YYYY-MM-DD | 2025-11-27 |\n| week | YYYY-Www | 2025-W48 |\n| month | YYYY-MM | 2025-11 |\n| quarter | YYYY-Qn | 2025-Q4 |\n| year | YYYY | 2025 |\n\n**Privacy Note:**\nAll segmentation is done on aggregate data only. No individual user journeys\nare exposed. Country data comes from request headers only - no IP geolocation.\n", "parameters": [{"name": "X-App-Key", "in": "header", "description": "App Key for authentication", "required": true, "type": "string"}, {"name": "conversion_events", "in": "query", "description": "REQUIRED: Comma-separated event names to count as conversions (e.g., purchase,subscription_complete)", "required": true, "type": "string"}, {"name": "segment_by", "in": "query", "description": "Segmentation type: platform (default), country, depth (events per session), or hour (0-23 UTC)", "required": false, "type": "string", "enum": ["platform", "country", "depth", "hour"]}, {"name": "granularity", "in": "query", "description": "Time period grouping: day (default), week, month, quarter, year", "required": false, "type": "string", "enum": ["day", "week", "month", "quarter", "year"]}, {"name": "from", "in": "query", "description": "Start date in YYYY-MM-DD format", "required": false, "type": "string"}, {"name": "to", "in": "query", "description": "End date in YYYY-MM-DD format", "required": false, "type": "string"}, {"name": "tz", "in": "query", "description": "IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Dates are interpreted in this timezone. Defaults to UTC.", "required": false, "type": "string", "default": "UTC"}], "responses": {"200": {"description": "Segment comparison data", "examples": {"application/json": {"app_name": "My App", "granularity": "month", "segment_by": "platform", "conversion_events": ["purchase"], "date_range": {"from": "2025-09-01", "to": "2025-11-27"}, "summary": {"total_segments": 2, "total_conversions": 570, "total_sessions": 8027, "overall_conversion_rate": 0.068}, "interpretation": "Session-scoped analysis: each unique session_id counted once per period", "segments": [{"segment": "iOS", "summary": {"total_active_sessions": 4497, "total_conversions": 359, "conversion_rate": 0.08}, "periods": [{"period": "2025-11", "active_sessions": 2341, "conversions": 187, "conversion_rate": 0.08}, {"period": "2025-10", "active_sessions": 2156, "conversions": 172, "conversion_rate": 0.08}]}, {"segment": "Android", "summary": {"total_active_sessions": 3530, "total_conversions": 211, "conversion_rate": 0.06}, "periods": [{"period": "2025-11", "active_sessions": 1876, "conversions": 112, "conversion_rate": 0.06}, {"period": "2025-10", "active_sessions": 1654, "conversions": 99, "conversion_rate": 0.06}]}]}}}, "400": {"description": "Bad Request - missing conversion_events or invalid parameters", "examples": {"application/json": {"error": "conversion_events parameter required", "detail": "Please specify which events to count as conversions.", "your_event_types": ["app_open", "screen_view", "button_click", "checkout_start", "payment_success"], "example": "?conversion_events=payment_success,checkout_start"}}}, "401": {"description": "Unauthorized - missing or invalid app_key"}}, "tags": ["v1"]}, "parameters": []}, "/v1/analytics/step-timing/": {"get": {"operationId": "v1_analytics_step-timing_list", "summary": "Analyze funnel step timing", "description": "\nAnalyze the time between consecutive steps in a user-defined funnel.\n\n**Session-Based Analysis:**\nThis endpoint analyzes events within the **same session_id**. This means:\n- Works for 100% of your sessions (including anonymous visitors)\n- No data quality warnings or exclusions\n- Perfect for in-session funnel analysis\n\n**Example Use Cases:**\n- How long does onboarding take? (`steps=onboarding_start,onboarding_complete`)\n- Where do sessions slow down in signup? (`steps=signup_start,email_entered,password_set,signup_complete`)\n- How long between pricing view and purchase? (`steps=pricing_view,purchase`)\n\n**Statistics Provided:**\n- Time between each consecutive step pair (median, mean, p25, p75 in seconds)\n- Number of sessions analyzed per transition\n- Overall funnel completion rate\n- Total funnel duration\n", "parameters": [{"name": "steps", "in": "query", "description": "Comma-separated list of funnel step event names (required, minimum 2)", "required": true, "type": "string"}, {"name": "start_date", "in": "query", "description": "Start date filter (YYYY-MM-DD)", "required": false, "type": "string", "format": "date"}, {"name": "end_date", "in": "query", "description": "End date filter (YYYY-MM-DD)", "required": false, "type": "string", "format": "date"}, {"name": "tz", "in": "query", "description": "IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Dates are interpreted in this timezone. Defaults to UTC.", "required": false, "type": "string", "default": "UTC"}], "responses": {"200": {"description": "Funnel step timing analysis", "examples": {"application/json": {"app": {"id": 1, "name": "My App", "slug": "my-app"}, "steps": ["onboarding_start", "onboarding_complete", "purchase"], "filters": {"start_date": null, "end_date": null}, "transitions": [{"from": "onboarding_start", "to": "onboarding_complete", "sessions_analyzed": 1234, "median_seconds": 45, "mean_seconds": 52, "p25_seconds": 30, "p75_seconds": 65}, {"from": "onboarding_complete", "to": "purchase", "sessions_analyzed": 234, "median_seconds": 120, "mean_seconds": 145, "p25_seconds": 60, "p75_seconds": 180}], "funnel_summary": {"sessions_with_first_step": 1234, "sessions_with_all_steps": 234, "completion_rate": 0.19, "median_total_seconds": 165, "mean_total_seconds": 197}}}}, "400": {"description": "Missing or invalid steps parameter"}, "401": {"description": "Unauthorized - missing or invalid app_key"}}, "tags": ["Analytics"]}, "parameters": []}, "/v1/analytics/time-to-conversion/": {"get": {"operationId": "v1_analytics_time-to-conversion_list", "summary": "Get time-to-conversion analysis", "description": "\nAnalyze how long it takes sessions to complete conversion events after their first\ninteraction with the app. This is a session-based analysis.\n\n**Required Parameters:**\n- `conversion_events`: Comma-separated conversion event names\n\n**Data Quality:**\n- Minimum 10 sessions with conversions required for meaningful analysis\n- Data quality metrics included in response\n\n**Statistics Provided:**\n- Median, mean, and percentiles (p25, p75, p90) for time-to-conversion\n- Time buckets: <5min, 5-15min, 15-60min, 1-2h (session-bounded)\n", "parameters": [{"name": "conversion_events", "in": "query", "description": "Comma-separated list of conversion event names (required)", "required": true, "type": "string"}, {"name": "start_date", "in": "query", "description": "Start date filter (YYYY-MM-DD)", "required": false, "type": "string", "format": "date"}, {"name": "end_date", "in": "query", "description": "End date filter (YYYY-MM-DD)", "required": false, "type": "string", "format": "date"}, {"name": "tz", "in": "query", "description": "IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Dates are interpreted in this timezone. Defaults to UTC.", "required": false, "type": "string", "default": "UTC"}], "responses": {"200": {"description": "Time-to-conversion analysis", "schema": {"type": "object", "properties": {"app": {"type": "object"}, "filters": {"type": "object"}, "data_quality": {"type": "object"}, "time_to_conversion": {"type": "object"}, "time_distribution": {"type": "object"}}}}, "400": {"description": "Missing required parameters or insufficient data"}, "401": {"description": "Unauthorized - missing or invalid app_key"}}, "tags": ["Analytics"]}, "parameters": []}, "/v1/events/": {"post": {"operationId": "v1_events_create", "description": "Submit an analytics event from your mobile app.\n\n**Privacy-First Validation:**\nRespectlytics enforces strict server-side privacy guards. Your request must:\n- Only include fields from the allowed list (see request body schema)\n- Use properly formatted session_id (16+ random chars, NOT UUID format)\n\n**Stored Fields:** Only these fields are persisted: event_name, session_id, timestamp, platform, country.\n\n**Deprecated Fields (accepted but ignored):** For backwards compatibility, these fields are still accepted but are NOT stored: device_type, os_version, app_version, locale, region, screen. Update your SDK to stop sending these fields.\n\n**Geolocation:** If you don't provide `country`, it will be automatically detected from your IP address. IP addresses are NEVER stored - they are used only for the lookup and immediately discarded.\n\n**Session Anonymization:** Session IDs are hashed with a daily-rotating salt before storage. This prevents cross-session tracking while enabling same-day funnel analysis.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["event_name"], "type": "object", "properties": {"event_name": {"description": "Event name (e.g., \"app_open\", \"purchase\")", "type": "string"}, "session_id": {"description": "Session identifier - must be 16+ random chars, NOT a UUID format. Anonymized with daily rotation.", "type": "string"}, "timestamp": {"description": "ISO 8601 timestamp - auto-set to current time if omitted", "type": "string"}, "platform": {"description": "Platform: ios, android, web, or other", "type": "string"}, "country": {"description": "Country code (e.g., \"US\") - auto-detected if omitted", "type": "string"}, "region": {"description": "DEPRECATED: Accepted but not stored", "type": "string"}, "device_type": {"description": "DEPRECATED: Accepted but not stored", "type": "string"}, "os_version": {"description": "DEPRECATED: Accepted but not stored", "type": "string"}, "app_version": {"description": "DEPRECATED: Accepted but not stored", "type": "string"}, "locale": {"description": "DEPRECATED: Accepted but not stored", "type": "string"}, "screen": {"description": "DEPRECATED: Accepted but not stored", "type": "string"}}}}, {"name": "X-App-Key", "in": "header", "description": "Your app's API key (UUID)", "required": true, "type": "string"}], "responses": {"201": {"description": "Event created successfully", "examples": {"application/json": {"id": 12345, "event_name": "purchase", "timestamp": "2025-11-12T10:30:00Z", "message": "Event created successfully"}}}, "400": {"description": "Bad Request - Privacy violation or invalid data", "schema": {"type": "object", "properties": {"detail": {"description": "Error summary", "type": "string"}, "code": {"description": "Error code: FORBIDDEN_FIELD, FORBIDDEN_FIELDS, or INVALID_SESSION_ID", "type": "string", "enum": ["FORBIDDEN_FIELD", "FORBIDDEN_FIELDS", "INVALID_SESSION_ID"]}, "reason": {"description": "Detailed explanation with fix instructions", "type": "string"}}}, "examples": {"application/json": {"FORBIDDEN_FIELD": {"detail": "Invalid request", "code": "FORBIDDEN_FIELD", "reason": "Field 'device_id' is not allowed. Respectlytics only accepts: app_key, app_version, country, device_type, event_name, locale, os_version, platform, region, screen, session_id, timestamp."}, "INVALID_SESSION_ID": {"detail": "Invalid request", "code": "INVALID_SESSION_ID", "reason": "session_id appears to be a device identifier or predictable pattern. Use a random string generated fresh for each app session."}}}}, "401": {"description": "Unauthorized - missing or invalid app_key", "examples": {"application/json": {"detail": "Authentication credentials were not provided."}}}}, "tags": ["v1"]}, "parameters": []}, "/v1/events/count/": {"get": {"operationId": "v1_events_count_list", "description": "GET /api/v1/events/count/ - Get fast event count for processing status\nQuery parameters:\n    - from: Start date (YYYY-MM-DD)\n    - to: End date (YYYY-MM-DD)\n\nReturns only the count without expensive aggregations.\nOptimized for showing processing banners with accurate event counts.", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["v1"]}, "parameters": []}, "/v1/events/delete/": {"post": {"operationId": "v1_events_delete_create", "description": "Permanently delete analytics events matching the given filters.\n\n**This action is irreversible.** All matching events will be permanently removed.\n\nDate range is required. Platform, country, and event_name are optional additional filters.\nA DeletionLog entry is created for audit purposes.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["date_from", "date_to"], "type": "object", "properties": {"date_from": {"description": "Start date (YYYY-MM-DD)", "type": "string"}, "date_to": {"description": "End date (YYYY-MM-DD)", "type": "string"}, "platform": {"description": "Optional: ios, android, web, other", "type": "string"}, "country": {"description": "Optional: ISO country code (e.g., \"US\")", "type": "string"}, "event_name": {"description": "Optional: specific event name", "type": "string"}}}}, {"name": "X-App-Key", "in": "header", "description": "Your app's API key (UUID)", "required": true, "type": "string"}], "responses": {"200": {"description": "Deletion completed", "examples": {"application/json": {"events_deleted": 1523, "deletion_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}}, "400": {"description": "Invalid request parameters"}}, "tags": ["v1"]}, "parameters": []}, "/v1/events/delete/preview/": {"post": {"operationId": "v1_events_delete_preview_create", "description": "Preview the number of events that would be deleted by the given filters.\n\nUse this endpoint to check how many events match before calling the delete endpoint.\nDate range is required. Platform, country, and event_name are optional additional filters.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["date_from", "date_to"], "type": "object", "properties": {"date_from": {"description": "Start date (YYYY-MM-DD)", "type": "string"}, "date_to": {"description": "End date (YYYY-MM-DD)", "type": "string"}, "platform": {"description": "Optional: ios, android, web, other", "type": "string"}, "country": {"description": "Optional: ISO country code (e.g., \"US\")", "type": "string"}, "event_name": {"description": "Optional: specific event name", "type": "string"}}}}, {"name": "X-App-Key", "in": "header", "description": "Your app's API key (UUID)", "required": true, "type": "string"}], "responses": {"200": {"description": "Count of matching events", "examples": {"application/json": {"events_matching": 1523}}}, "400": {"description": "Invalid request parameters"}}, "tags": ["v1"]}, "parameters": []}, "/v1/events/deletions/": {"get": {"operationId": "v1_events_deletions_list", "description": "Retrieve the deletion history for this app.\n\nReturns a list of all past event deletions with details about what was deleted and when.\nUseful for audit trail and demonstrating deletion request fulfilment.", "parameters": [{"name": "X-App-Key", "in": "header", "description": "Your app's API key (UUID)", "required": true, "type": "string"}], "responses": {"200": {"description": "List of deletion log entries", "examples": {"application/json": {"deletions": [{"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "deleted_at": "2026-02-10T14:30:00Z", "events_deleted": 1523, "filter_date_from": "2026-01-01", "filter_date_to": "2026-01-31", "filter_platform": null, "filter_country": "US", "filter_event_name": null}]}}}}, "tags": ["v1"]}, "parameters": []}, "/v1/events/event-types/": {"get": {"operationId": "v1_events_event-types_list", "description": "Get all distinct event types being tracked for your app", "parameters": [{"name": "X-App-Key", "in": "header", "description": "App Key for authentication", "required": true, "type": "string"}], "responses": {"200": {"description": "List of event types", "examples": {"application/json": {"app_name": "My Mobile App", "app_key": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "event_types": ["app_open", "product_view", "purchase", "share", "settings_open"], "count": 5}}}, "401": {"description": "Unauthorized - missing or invalid app_key"}}, "tags": ["v1"]}, "parameters": []}, "/v1/events/funnel/": {"get": {"operationId": "v1_events_funnel_list", "description": "Analyze conversion funnel through sequential event steps", "parameters": [{"name": "X-App-Key", "in": "header", "description": "App Key for authentication", "required": true, "type": "string"}, {"name": "steps", "in": "query", "description": "Comma-separated event names in order (e.g., 'app_open,product_view,purchase')", "required": true, "type": "string"}, {"name": "from", "in": "query", "description": "Start date in YYYY-MM-DD format", "required": false, "type": "string"}, {"name": "to", "in": "query", "description": "End date in YYYY-MM-DD format", "required": false, "type": "string"}, {"name": "tz", "in": "query", "description": "IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Dates are interpreted in this timezone. Defaults to UTC.", "required": false, "type": "string", "default": "UTC"}, {"name": "country", "in": "query", "description": "Filter by country code (e.g., 'US')", "required": false, "type": "string"}, {"name": "platform", "in": "query", "description": "Filter by platform (ios, android, web, other)", "required": false, "type": "string"}, {"name": "window_minutes", "in": "query", "description": "Step timeout in minutes - max time allowed between consecutive funnel steps (e.g., '30' for 30 minutes). Sessions are max 2 hours, so values above 120 have no effect. If not specified, no time limit is applied.", "required": false, "type": "integer"}], "responses": {"200": {"description": "Funnel analysis results", "examples": {"application/json": {"app_name": "My Mobile App", "app_key": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "funnel": [{"step": "app_open", "count": 1000}, {"step": "product_view", "count": 420}, {"step": "purchase", "count": 90}], "total_sessions_analyzed": 1200}}}, "400": {"description": "Bad request - missing or invalid parameters"}, "401": {"description": "Unauthorized - missing or invalid app_key"}}, "tags": ["v1"]}, "parameters": []}, "/v1/events/geo-summary/": {"get": {"operationId": "v1_events_geo-summary_list", "description": "Get geographic distribution of events for map visualizations", "parameters": [{"name": "X-App-Key", "in": "header", "description": "App Key for authentication", "required": true, "type": "string"}, {"name": "from", "in": "query", "description": "Start date in YYYY-MM-DD format", "required": false, "type": "string"}, {"name": "to", "in": "query", "description": "End date in YYYY-MM-DD format", "required": false, "type": "string"}, {"name": "tz", "in": "query", "description": "IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Dates are interpreted in this timezone. Defaults to UTC.", "required": false, "type": "string", "default": "UTC"}, {"name": "limit", "in": "query", "description": "Maximum results per category (default: 20)", "required": false, "type": "integer"}], "responses": {"200": {"description": "Geographic distribution data", "examples": {"application/json": {"app_name": "My Mobile App", "app_key": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "total_events": 15420, "countries": [{"country": "US", "count": 8500, "percentage": 55.1}, {"country": "CA", "count": 3200, "percentage": 20.8}, {"country": "UK", "count": 2100, "percentage": 13.6}]}}}, "400": {"description": "Bad Request - invalid date format"}, "401": {"description": "Unauthorized - missing or invalid app_key"}}, "tags": ["v1"]}, "parameters": []}, "/v1/events/summary/": {"get": {"operationId": "v1_events_summary_list", "description": "GET /api/v1/events/summary/ - Get aggregated event data (requires authentication)\nQuery parameters:\n    - from: Start date (YYYY-MM-DD)\n    - to: End date (YYYY-MM-DD)\n\nReturns data for the authenticated app.", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["v1"]}, "parameters": []}, "/v1/health/": {"get": {"operationId": "v1_health_list", "description": "Health check endpoint for load balancers and monitoring.\nReturns 200 if the service is healthy.", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["v1"]}, "parameters": []}}, "definitions": {}}