# Broadcast & Survey API Reference > **Base URL**: `https://api.bytelyst.io/v1` > **Authentication**: Bearer token (JWT) required for all endpoints except public ones > **Product ID**: All requests must include `X-Product-ID` header --- ## Authentication ```http Authorization: Bearer X-Product-ID: ``` --- ## Broadcasts ### Admin Endpoints #### List Broadcasts ```http GET /admin/broadcasts ``` **Query Parameters:** | Parameter | Type | Description | |-----------|------|-------------| | `status` | string | Filter by status: `draft`, `scheduled`, `sending`, `paused`, `completed` | | `channel` | string | Filter by channel: `push`, `in_app`, `email`, `sms` | | `limit` | integer | Max items (default: 20, max: 100) | | `offset` | integer | Pagination offset | **Response:** ```json { "broadcasts": [ { "id": "bc_123456789", "productId": "lysnrai", "title": "New Feature Announcement", "body": "Check out our latest update!", "channel": "push", "priority": "high", "status": "completed", "target": { "platforms": ["ios", "android"], "userSegments": ["pro"], "percentageRollout": 100 }, "metrics": { "targetedCount": 1500, "sentCount": 1500, "deliveredCount": 1420, "openedCount": 890, "clickedCount": 340, "dismissedCount": 45 }, "createdAt": "2024-01-15T10:30:00Z", "updatedAt": "2024-01-15T10:35:00Z" } ], "total": 47, "limit": 20, "offset": 0 } ``` --- #### Get Broadcast ```http GET /admin/broadcasts/:id ``` **Response:** Single broadcast object (same as list item) --- #### Create Broadcast ```http POST /admin/broadcasts ``` **Request Body:** ```json { "title": "New Feature Announcement", "body": "Check out our latest update with voice commands!", "channel": "push", "priority": "high", "style": "banner", "ctaText": "Try it now", "ctaUrl": "https://app.bytelyst.io/voice", "imageUrl": "https://cdn.bytelyst.io/banner/voice.jpg", "target": { "platforms": ["ios", "android"], "userSegments": ["pro"], "appVersionMin": "2.0.0", "appVersionMax": null, "countryCodes": ["US", "CA"], "percentageRollout": 100, "specificUserIds": null }, "scheduledAt": "2024-01-20T09:00:00Z", "expiresAt": "2024-02-20T09:00:00Z", "deepLink": { "screen": "voice_settings", "params": { "tab": "commands" } } } ``` **Response:** Created broadcast object with `id` --- #### Update Broadcast ```http PUT /admin/broadcasts/:id ``` **Request Body:** Partial broadcast object (same as create) **Response:** Updated broadcast object --- #### Delete Broadcast ```http DELETE /admin/broadcasts/:id ``` **Response:** `204 No Content` --- #### Send Broadcast ```http POST /admin/broadcasts/:id/send ``` Triggers immediate send (or schedules if `scheduledAt` is set). **Response:** ```json { "success": true, "message": "Broadcast queued for sending", "estimatedReach": 1500 } ``` --- #### Pause Broadcast ```http POST /admin/broadcasts/:id/pause ``` Pauses a sending broadcast. **Response:** ```json { "success": true, "message": "Broadcast paused" } ``` --- #### Get Broadcast Metrics ```http GET /admin/broadcasts/:id/metrics ``` **Response:** ```json { "targetedCount": 1500, "sentCount": 1500, "deliveredCount": 1420, "openedCount": 890, "clickedCount": 340, "dismissedCount": 45, "convertedCount": 120, "deliveryRate": 94.7, "openRate": 59.3, "clickRate": 22.7, "conversionRate": 8.0 } ``` --- #### Clone Broadcast ```http POST /admin/broadcasts/:id/clone ``` Creates a copy of the broadcast as a draft. **Response:** New broadcast object with `id` --- ### Public Endpoints (Authenticated) #### List In-App Messages ```http GET /public/messages/in-app ``` Returns active in-app messages for the authenticated user. **Response:** ```json { "messages": [ { "id": "msg_987654321", "broadcastId": "bc_123456789", "title": "New Feature Announcement", "body": "Check out our latest update!", "style": "banner", "priority": "high", "ctaText": "Try it now", "ctaUrl": "https://app.bytelyst.io/voice", "imageUrl": "https://cdn.bytelyst.io/banner/voice.jpg", "deepLink": { "screen": "voice_settings", "params": { "tab": "commands" } }, "status": "unread", "createdAt": "2024-01-15T10:30:00Z" } ] } ``` --- #### Mark Message Read ```http POST /public/messages/:id/read ``` **Response:** ```json { "success": true, "message": "Marked as read" } ``` --- #### Dismiss Message ```http POST /public/messages/:id/dismiss ``` **Response:** ```json { "success": true, "message": "Message dismissed" } ``` --- #### Track Message Click ```http POST /public/messages/:id/click ``` **Response:** ```json { "success": true, "message": "Click tracked" } ``` --- ## Surveys ### Admin Endpoints #### List Surveys ```http GET /admin/surveys ``` **Query Parameters:** | Parameter | Type | Description | |-----------|------|-------------| | `status` | string | Filter by status: `draft`, `active`, `paused`, `completed` | | `limit` | integer | Max items (default: 20, max: 100) | | `offset` | integer | Pagination offset | **Response:** ```json { "surveys": [ { "id": "srv_123456789", "productId": "lysnrai", "title": "Product Feedback Survey", "description": "Help us improve your experience", "status": "active", "questionCount": 5, "responseCount": 892, "incentive": { "type": "pro_days", "amount": 7 }, "createdAt": "2024-01-10T08:00:00Z", "updatedAt": "2024-01-15T14:30:00Z" } ], "total": 12, "limit": 20, "offset": 0 } ``` --- #### Get Survey ```http GET /admin/surveys/:id ``` **Response:** Full survey with questions ```json { "id": "srv_123456789", "productId": "lysnrai", "title": "Product Feedback Survey", "description": "Help us improve your experience", "status": "active", "questions": [ { "id": "q1", "type": "nps", "text": "How likely are you to recommend us?", "required": true, "minValue": 0, "maxValue": 10 }, { "id": "q2", "type": "single_choice", "text": "What feature do you use most?", "required": true, "options": [ { "id": "voice", "text": "Voice dictation", "emoji": "🎙️" }, { "id": "keyboard", "text": "Keyboard", "emoji": "⌨️" }, { "id": "desktop", "text": "Desktop app", "emoji": "💻" } ] } ], "target": { "platforms": ["ios", "android"], "userSegments": ["active"] }, "displayTrigger": { "type": "delay_seconds", "seconds": 30 }, "incentive": { "type": "pro_days", "amount": 7 }, "metrics": { "startedCount": 1200, "completedCount": 892, "completionRate": 74.3 }, "createdAt": "2024-01-10T08:00:00Z", "updatedAt": "2024-01-15T14:30:00Z" } ``` --- #### Create Survey ```http POST /admin/surveys ``` **Request Body:** ```json { "title": "Product Feedback Survey", "description": "Help us improve your experience", "questions": [ { "id": "q1", "type": "nps", "text": "How likely are you to recommend us?", "required": true, "minValue": 0, "maxValue": 10 }, { "id": "q2", "type": "single_choice", "text": "What feature do you use most?", "description": "Select your primary use case", "required": true, "options": [ { "id": "voice", "text": "Voice dictation", "emoji": "🎙️" }, { "id": "keyboard", "text": "Keyboard", "emoji": "⌨️" } ] }, { "id": "q3", "type": "text_long", "text": "What could we improve?", "required": false, "maxLength": 500, "showIf": { "questionId": "q1", "operator": "not_equals", "value": ["9", "10"] } } ], "target": { "platforms": ["ios", "android"], "userSegments": ["active"], "percentageRollout": 100 }, "displayTrigger": { "type": "delay_seconds", "seconds": 30 }, "incentive": { "type": "pro_days", "amount": 7 } } ``` **Response:** Created survey object with `id` --- #### Update Survey ```http PUT /admin/surveys/:id ``` **Request Body:** Partial survey object **Response:** Updated survey object --- #### Delete Survey ```http DELETE /admin/surveys/:id ``` **Response:** `204 No Content` --- #### Get Survey Metrics ```http GET /admin/surveys/:id/metrics ``` **Response:** ```json { "questionStats": [ { "questionId": "q1", "questionType": "nps", "responseCount": 892, "distribution": { "0": 12, "1": 8, "2": 15, "7": 120, "8": 200, "9": 180, "10": 357 }, "average": 8.2, "npsScore": 68 } ], "startedCount": 1200, "completedCount": 892, "completionRate": 74.3, "averageTimeSeconds": 145 } ``` --- #### Export Survey Responses ```http GET /admin/surveys/:id/export ``` **Query Parameters:** | Parameter | Type | Description | |-----------|------|-------------| | `format` | string | `csv` or `json` (default: `csv`) | **Response:** File download (CSV or JSON) CSV format: ```csv response_id,user_id,started_at,completed_at,q1,q2,q3 resp_abc123,user_xyz,2024-01-15T10:30:00Z,2024-01-15T10:32:45Z,8,voice,Make it faster ``` --- ### Public Endpoints (Authenticated) #### Get Active Survey ```http GET /public/surveys/active ``` Returns the active survey for the authenticated user, if any. **Response:** ```json { "id": "srv_123456789", "title": "Product Feedback Survey", "description": "Help us improve your experience", "questions": [ { "id": "q1", "type": "nps", "text": "How likely are you to recommend us?", "required": true, "minValue": 0, "maxValue": 10 } ], "currentQuestionIndex": 0, "incentive": { "type": "pro_days", "amount": 7 } } ``` Or `204 No Content` if no active survey. --- #### Start Survey ```http POST /public/surveys/:id/start ``` **Response:** ```json { "success": true, "surveyStateId": "ss_987654321", "currentQuestionIndex": 0 } ``` --- #### Submit Answer ```http POST /public/surveys/:id/answers ``` **Request Body:** ```json { "questionId": "q1", "answer": { "type": "rating", "value": { "value": 8 } } } ``` **Response:** ```json { "success": true, "currentQuestionIndex": 1, "nextQuestionId": "q2", "isComplete": false } ``` --- #### Complete Survey ```http POST /public/surveys/:id/complete ``` **Response:** ```json { "success": true, "incentiveClaimed": true, "incentiveType": "pro_days", "incentiveAmount": 7 } ``` --- #### Dismiss Survey ```http POST /public/surveys/:id/dismiss ``` **Response:** ```json { "success": true, "message": "Survey dismissed" } ``` --- ## Types Reference ### Broadcast Status | Status | Description | |--------|-------------| | `draft` | Created but not yet sent | | `scheduled` | Scheduled for future send | | `sending` | Currently being sent | | `paused` | Send paused by admin | | `completed` | Fully sent and finished | ### Message Priority | Priority | Description | |----------|-------------| | `low` | Silent delivery, no badge | | `normal` | Standard notification | | `high` | Prominent with sound | | `urgent` | Critical, persistent alert | ### Message Style | Style | Description | |-------|-------------| | `banner` | Top/bottom banner | | `modal` | Center dialog | | `fullscreen` | Full-screen takeover | | `toast` | Brief ephemeral message | ### Survey Question Types | Type | Description | |------|-------------| | `single_choice` | Radio button selection | | `multiple_choice` | Checkbox multi-select | | `rating` | Star rating (1-5) | | `scale` | Numeric scale | | `nps` | Net Promoter Score (0-10) | | `text_short` | Single line text | | `text_long` | Multi-line textarea | | `ranking` | Drag-to-order items | | `dropdown` | Single select dropdown | --- ## Error Responses All errors follow this format: ```json { "error": { "code": "NOT_FOUND", "message": "Broadcast not found", "requestId": "req_abc123" } } ``` ### Error Codes | Code | HTTP Status | Description | |------|-------------|-------------| | `BAD_REQUEST` | 400 | Invalid request data | | `UNAUTHORIZED` | 401 | Missing or invalid token | | `FORBIDDEN` | 403 | Insufficient permissions | | `NOT_FOUND` | 404 | Resource not found | | `CONFLICT` | 409 | Resource already exists | | `RATE_LIMITED` | 429 | Too many requests | | `INTERNAL_ERROR` | 500 | Server error | --- ## Rate Limits | Endpoint Group | Limit | |----------------|-------| | Admin endpoints | 100 req/min per user | | Public endpoints | 60 req/min per user | | Message tracking | 1000 req/min per user | --- ## Webhooks Events sent to configured webhook URLs: ### Broadcast Events - `broadcast.created` - `broadcast.sent` - `broadcast.completed` - `broadcast.read` - `broadcast.clicked` ### Survey Events - `survey.created` - `survey.started` - `survey.completed` - `survey.response_submitted` **Webhook Payload:** ```json { "event": "broadcast.clicked", "timestamp": "2024-01-15T10:32:15Z", "data": { "broadcastId": "bc_123456789", "userId": "user_xyz", "messageId": "msg_987654321" } } ```