{"openapi":"3.0.3","info":{"title":"Sendy API","description":"Multi-channel communication platform with AI-powered responses.\n\n## Authentication\nAll endpoints require a Bearer token (API key). Create one in the dashboard under **Settings → API Keys**.\n\n```\nAuthorization: Bearer sk_your_api_key_here\n```\n\n## Rate Limits\nAPI keys are rate-limited to **100 requests/minute**. Batch endpoints count as a single request.\n\n## Errors\nAll errors follow a consistent format:\n```json\n{ \"success\": false, \"error\": { \"code\": \"ERROR_CODE\", \"message\": \"Human-readable message\" } }\n```","version":"1.20.0","contact":{"name":"Sendy Support","url":"https://sendy.ozapp.io"}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key starting with `sk_...` — get one from Settings → API Keys in the dashboard."}},"schemas":{}},"paths":{"/api/v1/emails/send":{"post":{"summary":"Send an email","tags":["Emails"],"description":"Send a single email or schedule it for later delivery. Requires `email.send` permission.\n\nAttachments may be passed inline as base64 in the `attachments` array. Total request body is capped at ~1 MB; for larger files use `POST /emails/send/multipart` (50 MB per file, up to 10 files).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to","subject"],"properties":{"to":{"anyOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1}],"description":"Recipient email address or array of addresses"},"cc":{"anyOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"}}],"description":"CC recipient(s)"},"bcc":{"anyOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"}}],"description":"BCC recipient(s)"},"reply_to":{"type":"string","format":"email","description":"Reply-to address"},"from_name":{"type":"string","minLength":1,"maxLength":100,"description":"Optional display-name override for the `From:` header. The email address itself is always the SMTP account's `from_email` to preserve DKIM/SPF/DMARC validity."},"subject":{"type":"string","minLength":1,"maxLength":998},"html":{"type":"string","description":"HTML body content"},"text":{"type":"string","description":"Plain text body content"},"scheduled_at":{"type":"string","format":"date-time","description":"Schedule send time (ISO 8601)"},"smtpAccountId":{"type":"string","format":"uuid","description":"Required when the API key is bound to multiple SMTP accounts (or has allow-all SMTP access). Either pass `smtpAccountId` or the convenience `from_email` field; if both are present, `smtpAccountId` wins."},"from_email":{"type":"string","format":"email","description":"Convenience selector: pick the SMTP account by its configured `from_email` instead of its id. Must be authorized by this API key."},"attachments":{"type":"array","items":{"type":"object","required":["filename","content"],"properties":{"filename":{"type":"string"},"content":{"type":"string","description":"Base64-encoded file content"},"content_type":{"type":"string","description":"MIME type"}}}}},"example":{"to":"recipient@example.com","subject":"Welcome to Sendy","html":"<h1>Welcome!</h1><p>Thanks for signing up.</p>","text":"Welcome! Thanks for signing up."}}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued"]},"scheduled_at":{"type":"string","format":"date-time","nullable":true}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/emails/send/multipart":{"post":{"summary":"Send email with attachments (multipart)","tags":["Emails"],"description":"Send an email using `multipart/form-data` for file attachments. Requires `email.send` permission.\n\n**Text fields** (same names and semantics as `POST /emails/send`):\n- `to` (required) — single email or comma-separated / JSON array\n- `cc`, `bcc` — same format as `to`\n- `subject` (required), `html`, `text`, `reply_to`, `scheduled_at`\n- `from_name` — optional display-name override (1–100 chars). The email address stays bound to the SMTP account.\n\n**File parts** — every file part is treated as an attachment, regardless of the field name (`attachments`, `attachment`, `file`, `files`, `files[]`, etc. all work). The original `filename` and `mimetype` are preserved.\n\n**Limits**: 50 MB per file, 10 files per request. For files larger than 50 MB or batched JSON workflows, use `POST /emails/send` with base64-encoded attachments (body capped at ~1 MB).","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued"]},"scheduled_at":{"type":"string","format":"date-time","nullable":true}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/emails/batch":{"post":{"summary":"Batch send emails","tags":["Emails"],"description":"Send emails to multiple recipients with optional template variables. Max 500 recipients. Requires `email.send` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["recipients","subject"],"properties":{"recipients":{"type":"array","minItems":1,"maxItems":500,"items":{"type":"object","required":["to"],"properties":{"to":{"type":"string","format":"email"},"variables":{"type":"object","additionalProperties":{"type":"string"},"description":"Template variables for {{key}} replacement"}}}},"subject":{"type":"string","minLength":1,"maxLength":998},"html":{"type":"string","description":"HTML body content (supports {{variable}} placeholders)"},"text":{"type":"string","description":"Plain text body content (supports {{variable}} placeholders)"},"reply_to":{"type":"string","format":"email"},"from_name":{"type":"string","minLength":1,"maxLength":100,"description":"Optional display-name override applied to every recipient in the batch. The email address itself stays bound to the SMTP account for DKIM/SPF validity."}},"example":{"recipients":[{"to":"alice@example.com","variables":{"name":"Alice"}},{"to":"bob@example.com","variables":{"name":"Bob"}}],"subject":"Hello {{name}}!","html":"<p>Hi {{name}}, welcome aboard.</p>"}}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"to":{"type":"string","format":"email"},"status":{"type":"string","enum":["queued"]}}}},"meta":{"type":"object","properties":{"total":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/emails":{"get":{"summary":"List sent emails","tags":["Emails"],"description":"Retrieve a paginated list of sent emails with optional filters. Requires `email.history` permission.","parameters":[{"schema":{"type":"string"},"in":"query","name":"status","required":false,"description":"Filter by status (queued, sending, sent, failed, bounced, cancelled)"},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"date_from","required":false,"description":"Filter from date (ISO 8601)"},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"date_to","required":false,"description":"Filter to date (ISO 8601)"},{"schema":{"type":"string"},"in":"query","name":"recipient","required":false,"description":"Filter by recipient email (partial match)"},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"per_page","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"fromEmail":{"type":"string","format":"email"},"fromName":{"type":"string","nullable":true},"toEmails":{"type":"array","items":{"type":"string","format":"email"}},"subject":{"type":"string"},"status":{"type":"string"},"scheduledAt":{"type":"string","format":"date-time","nullable":true},"sentAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"_count":{"type":"object","properties":{"attachments":{"type":"integer"},"trackingEvents":{"type":"integer"}}}}}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/emails/{id}":{"get":{"summary":"Get email details","tags":["Emails"],"description":"Retrieve a single email with attachments, tracking events, and bounces. Requires `email.history` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"smtpAccountId":{"type":"string","format":"uuid"},"fromEmail":{"type":"string","format":"email"},"fromName":{"type":"string","nullable":true},"toEmails":{"type":"array","items":{"type":"string","format":"email"}},"ccEmails":{"type":"array","items":{"type":"string"},"nullable":true},"bccEmails":{"type":"array","items":{"type":"string"},"nullable":true},"replyTo":{"type":"string","nullable":true},"subject":{"type":"string"},"htmlBody":{"type":"string","nullable":true},"textBody":{"type":"string","nullable":true},"messageId":{"type":"string","nullable":true,"description":"SMTP Message-ID header assigned after sending"},"status":{"type":"string"},"scheduledAt":{"type":"string","format":"date-time","nullable":true},"sentAt":{"type":"string","format":"date-time","nullable":true},"errorMessage":{"type":"string","nullable":true,"description":"Error details if status is failed"},"createdAt":{"type":"string","format":"date-time"},"attachments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"filename":{"type":"string"},"contentType":{"type":"string"},"sizeBytes":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"}}}},"trackingEvents":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["open","click"]},"url":{"type":"string","nullable":true},"ipAddress":{"type":"string","nullable":true},"userAgent":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}}}},"bounces":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","description":"Bounce type: hard or soft"},"code":{"type":"string","nullable":true,"description":"SMTP bounce code"},"reason":{"type":"string","nullable":true,"description":"Bounce reason / diagnostic message"},"createdAt":{"type":"string","format":"date-time"}}}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/emails/{id}/cancel":{"delete":{"summary":"Cancel a scheduled email","tags":["Emails"],"description":"Cancel a queued/scheduled email before it is sent. Only emails with status `queued` can be cancelled. Requires `email.send` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["cancelled"]},"queue_removed":{"type":"boolean","description":"Whether the job was removed from the processing queue"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/tracking/{emailId}":{"get":{"summary":"Get tracking events for an email","tags":["Tracking"],"description":"Retrieve all open and click tracking events for a specific email. Requires `tracking.read` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"emailId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"emailId":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["open","click"]},"url":{"type":"string","nullable":true},"ipAddress":{"type":"string","nullable":true},"userAgent":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/stats":{"get":{"summary":"Get SMTP account stats","tags":["Tracking"],"description":"Get aggregated email stats (sent, opened, clicked, bounced, etc.) for the authenticated SMTP account over a given period. Defaults to last 30 days. Requires `tracking.read` permission.","parameters":[{"schema":{"type":"string","format":"date-time"},"in":"query","name":"from","required":false,"description":"Period start (ISO 8601). Defaults to 30 days ago."},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"to","required":false,"description":"Period end (ISO 8601). Defaults to now."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"total_sent":{"type":"integer"},"total_opened":{"type":"integer"},"total_clicked":{"type":"integer"},"total_bounced":{"type":"integer"},"total_failed":{"type":"integer"},"total_queued":{"type":"integer"},"total_sending":{"type":"integer"},"total_delivered":{"type":"integer","description":"Emails confirmed delivered via DSN"},"total_read":{"type":"integer","description":"Emails with a confirmed read-receipt (MDN)"},"total_replied":{"type":"integer","description":"Emails that received a reply"},"open_rate":{"type":"number","description":"Open rate percentage"},"click_rate":{"type":"number","description":"Click rate percentage"},"bounce_rate":{"type":"number","description":"Bounce rate percentage"},"delivery_rate":{"type":"number","description":"DSN-confirmed delivery rate percentage"},"read_rate":{"type":"number","description":"MDN-confirmed read rate percentage"},"reply_rate":{"type":"number","description":"Reply rate percentage"},"period":{"type":"object","properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"}}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/inbox":{"get":{"summary":"List inbox messages","tags":["Inbox"],"description":"Retrieve a paginated list of received emails from IMAP accounts linked to the API key's SMTP account. Requires `email.inbox_read` permission.","parameters":[{"schema":{"type":"string"},"in":"query","name":"from","required":false,"description":"Filter by sender email (partial match, case-insensitive)"},{"schema":{"type":"string"},"in":"query","name":"subject","required":false,"description":"Filter by subject (partial match, case-insensitive)"},{"schema":{"type":"string","enum":["true","false"]},"in":"query","name":"is_read","required":false,"description":"Filter by read status"},{"schema":{"type":"string"},"in":"query","name":"folder","required":false,"description":"Filter by IMAP folder (e.g. INBOX, Sent)"},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"date_from","required":false,"description":"Filter from date (ISO 8601)"},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"date_to","required":false,"description":"Filter to date (ISO 8601)"},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"per_page","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"messageId":{"type":"string"},"fromEmail":{"type":"string"},"fromName":{"type":"string","nullable":true},"replyToEmail":{"type":"string","nullable":true},"toEmail":{"type":"string"},"subject":{"type":"string","nullable":true},"isRead":{"type":"boolean"},"isFlagged":{"type":"boolean"},"hasAttachments":{"type":"boolean"},"folder":{"type":"string"},"receivedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"_count":{"type":"object","properties":{"attachments":{"type":"integer"}}}}}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/inbox/{id}":{"get":{"summary":"Get inbox message","tags":["Inbox"],"description":"Retrieve a single inbox message with full body content and attachment metadata. Requires `email.inbox_read` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"messageId":{"type":"string"},"fromEmail":{"type":"string"},"fromName":{"type":"string","nullable":true},"replyToEmail":{"type":"string","nullable":true},"toEmail":{"type":"string"},"subject":{"type":"string","nullable":true},"htmlBody":{"type":"string","nullable":true},"textBody":{"type":"string","nullable":true},"isRead":{"type":"boolean"},"isFlagged":{"type":"boolean"},"hasAttachments":{"type":"boolean"},"folder":{"type":"string"},"receivedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"attachments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"filename":{"type":"string"},"contentType":{"type":"string"},"sizeBytes":{"type":"integer"}}}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}},"delete":{"summary":"Delete inbox message","tags":["Inbox"],"description":"Soft-delete an inbox message and sync the deletion to the IMAP server. Requires `email.inbox_reply` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"deleted":{"type":"boolean","enum":[true]}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/inbox/{id}/read":{"patch":{"summary":"Toggle read status","tags":["Inbox"],"description":"Mark an inbox message as read or unread. Syncs the \\Seen flag to the IMAP server. Requires `email.inbox_read` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["is_read"],"properties":{"is_read":{"type":"boolean"}},"example":{"is_read":true}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"isRead":{"type":"boolean"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/inbox/{id}/flag":{"patch":{"summary":"Toggle flagged status","tags":["Inbox"],"description":"Toggle the flagged (starred) status of an inbox message. Syncs the \\Flagged flag to the IMAP server. Requires `email.inbox_read` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["is_flagged"],"properties":{"is_flagged":{"type":"boolean"}},"example":{"is_flagged":true}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"isFlagged":{"type":"boolean"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/inbox/{id}/move":{"patch":{"summary":"Move message to folder","tags":["Inbox"],"description":"Move an inbox message to a different IMAP folder (e.g. INBOX, Archive, Trash). Requires `email.inbox_read` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["folder"],"properties":{"folder":{"type":"string","minLength":1,"description":"Target IMAP folder name"}},"example":{"folder":"Archive"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"folder":{"type":"string"},"imapUid":{"type":"integer","nullable":true}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/inbox/{id}/attachments/{attachmentId}":{"get":{"summary":"Download attachment","tags":["Inbox"],"description":"Download a specific attachment from an inbox message. Returns the file as a binary stream. Requires `email.inbox_read` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"Inbox message ID"},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"attachmentId","required":true,"description":"Attachment ID"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Binary file content","content":{"application/json":{"schema":{"description":"Binary file content","type":"string","format":"binary"}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/suppressions":{"get":{"summary":"List suppressions","tags":["Suppressions"],"description":"Retrieve a paginated list of suppressed email addresses. Optionally filter by reason. Requires `suppressions` permission (read or write).","parameters":[{"schema":{"type":"string","enum":["bounce","unsubscribe","spam_complaint","manual"]},"in":"query","name":"reason","required":false,"description":"Filter by suppression reason"},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"in":"query","name":"per_page","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"reason":{"type":"string","enum":["bounce","unsubscribe","spam_complaint","manual"]},"source_email_id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string","format":"date-time"}}}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}}}}}}}}},"post":{"summary":"Add suppression","tags":["Suppressions"],"description":"Manually add an email address to the suppression list. If the email is already suppressed, the reason will be updated. Requires `suppressions` permission (read or write).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"reason":{"type":"string","enum":["bounce","unsubscribe","spam_complaint","manual"],"default":"manual"},"smtpAccountId":{"type":"string","format":"uuid","description":"Required when the API key is bound to multiple SMTP accounts (or has allow-all SMTP access). Picks which account's suppression list to write to. Omit for single-binding keys."}},"example":{"email":"bounced-user@example.com","reason":"manual"}}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"reason":{"type":"string","enum":["bounce","unsubscribe","spam_complaint","manual"]},"source_email_id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/suppressions/{email}":{"delete":{"summary":"Remove suppression","tags":["Suppressions"],"description":"Remove an email address from the suppression list. Requires `suppressions` permission (read or write).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"smtpAccountId","required":false,"description":"Required when the API key is bound to multiple SMTP accounts (or has allow-all SMTP access). Picks which account's suppression list to delete from. Omit for single-binding keys."},{"schema":{"type":"string","format":"email"},"in":"path","name":"email","required":true,"description":"Email address to remove"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/smtp-accounts":{"get":{"summary":"List SMTP accounts available to this API key","tags":["Emails"],"description":"Returns the SMTP accounts authorized by this API key. Use the returned `id` as `smtpAccountId` in `POST /emails/send` when the key is bound to multiple accounts.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"fromEmail":{"type":"string","format":"email"},"fromName":{"type":"string","nullable":true},"isActive":{"type":"boolean"}}}},"meta":{"type":"object","properties":{"allowAll":{"type":"boolean","description":"When true, this key may use any SMTP account of its organization (including future ones)."},"total":{"type":"integer"}}}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/verify":{"post":{"summary":"Verify email address","tags":["Verification"],"description":"Verify a single email address by checking syntax, MX records, and disposable domain status. Requires `verify.use` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","description":"Email address to verify"}},"example":{"email":"check-this@example.com"}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"email":{"type":"string","format":"email"},"is_valid":{"type":"boolean"},"checks":{"type":"object","properties":{"syntax":{"type":"object","properties":{"valid":{"type":"boolean"},"reason":{"type":"string"}}},"mx":{"type":"object","properties":{"valid":{"type":"boolean"},"records":{"type":"array","items":{"type":"string"}},"reason":{"type":"string"}}},"disposable":{"type":"object","properties":{"is_disposable":{"type":"boolean"}}}}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/verify/batch":{"post":{"summary":"Batch verify emails","tags":["Verification"],"description":"Verify multiple email addresses at once (max 100). Returns verification results for each email. Requires `verify.use` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["emails"],"properties":{"emails":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":100,"description":"Array of email addresses to verify"}},"example":{"emails":["alice@example.com","bob@test.com","invalid@nonexistent.xyz"]}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","format":"email"},"is_valid":{"type":"boolean"},"checks":{"type":"object","properties":{"syntax":{"type":"object","properties":{"valid":{"type":"boolean"},"reason":{"type":"string"}}},"mx":{"type":"object","properties":{"valid":{"type":"boolean"},"records":{"type":"array","items":{"type":"string"}},"reason":{"type":"string"}}},"disposable":{"type":"object","properties":{"is_disposable":{"type":"boolean"}}}}}}}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"valid":{"type":"integer"},"invalid":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/webhooks":{"get":{"summary":"List webhooks","tags":["Webhooks"],"description":"Retrieve all webhooks for the authenticated SMTP account. Requires `webhooks.read` permission.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["email.queued","email.sent","email.failed","email.opened","email.clicked","email.bounced","email.unsubscribed","email.received","email.delivered","email.read","email.replied","smtp.up","smtp.down","smtp.blacklisted","warmup.completed","imap.connection_failed","imap.recovered","whatsapp.sent","whatsapp.delivered","whatsapp.read","whatsapp.failed","whatsapp.received","whatsapp.provider_switched","whatsapp.disconnected","whatsapp.reconnected","whatsapp.banned","sms.sent","sms.delivered","sms.failed","sms.received","sms.gateway_offline","sms.gateway_online","ai.draft_ready","ai.responded","ai.escalated"]}},"is_active":{"type":"boolean"},"smtp_account_id":{"type":"string","format":"uuid","nullable":true,"description":"If set, this webhook only fires for events from this SMTP account. Null = org-wide."},"whatsapp_account_id":{"type":"string","format":"uuid","nullable":true,"description":"If set, this webhook only fires for events from this WhatsApp account. Null = org-wide."},"sms_gateway_id":{"type":"string","format":"uuid","nullable":true,"description":"If set, this webhook only fires for events from this SMS gateway. Null = org-wide."},"created_at":{"type":"string","format":"date-time"}}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}},"post":{"summary":"Create webhook","tags":["Webhooks"],"description":"Create a new webhook endpoint. A signing secret is auto-generated. URL must use HTTPS. Requires `webhooks.write` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","events"],"properties":{"url":{"type":"string","format":"uri","description":"The URL to receive webhook events"},"events":{"type":"array","items":{"type":"string","enum":["email.queued","email.sent","email.failed","email.opened","email.clicked","email.bounced","email.unsubscribed","email.received","email.delivered","email.read","email.replied","smtp.up","smtp.down","smtp.blacklisted","warmup.completed","imap.connection_failed","imap.recovered","whatsapp.sent","whatsapp.delivered","whatsapp.read","whatsapp.failed","whatsapp.received","whatsapp.provider_switched","whatsapp.disconnected","whatsapp.reconnected","whatsapp.banned","sms.sent","sms.delivered","sms.failed","sms.received","sms.gateway_offline","sms.gateway_online","ai.draft_ready","ai.responded","ai.escalated"]},"minItems":1,"description":"List of event types to subscribe to"},"smtp_account_id":{"type":"string","format":"uuid","description":"Optional: only fire for events from this SMTP account. Omit for org-wide."},"whatsapp_account_id":{"type":"string","format":"uuid","description":"Optional: only fire for events from this WhatsApp account. Omit for org-wide."},"sms_gateway_id":{"type":"string","format":"uuid","description":"Optional: only fire for events from this SMS gateway. Omit for org-wide."}},"example":{"url":"https://your-app.com/webhooks/sendy","events":["whatsapp.received","whatsapp.delivered"],"whatsapp_account_id":"055330af-8831-4703-8be1-209bb5a4703f"}}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"}},"secret":{"type":"string","description":"HMAC signing secret (only returned on creation)"},"is_active":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/webhooks/{id}":{"patch":{"summary":"Update webhook","tags":["Webhooks"],"description":"Update a webhook's URL, events, or active status. Requires `webhooks.write` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["email.queued","email.sent","email.failed","email.opened","email.clicked","email.bounced","email.unsubscribed","email.received","email.delivered","email.read","email.replied","smtp.up","smtp.down","smtp.blacklisted","warmup.completed","imap.connection_failed","imap.recovered","whatsapp.sent","whatsapp.delivered","whatsapp.read","whatsapp.failed","whatsapp.received","whatsapp.provider_switched","whatsapp.disconnected","whatsapp.reconnected","whatsapp.banned","sms.sent","sms.delivered","sms.failed","sms.received","sms.gateway_offline","sms.gateway_online","ai.draft_ready","ai.responded","ai.escalated"]},"minItems":1},"is_active":{"type":"boolean"}},"example":{"events":["email.sent","email.bounced","email.opened","email.clicked"],"is_active":true}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["email.queued","email.sent","email.failed","email.opened","email.clicked","email.bounced","email.unsubscribed","email.received","email.delivered","email.read","email.replied","smtp.up","smtp.down","smtp.blacklisted","warmup.completed","imap.connection_failed","imap.recovered","whatsapp.sent","whatsapp.delivered","whatsapp.read","whatsapp.failed","whatsapp.received","whatsapp.provider_switched","whatsapp.disconnected","whatsapp.reconnected","whatsapp.banned","sms.sent","sms.delivered","sms.failed","sms.received","sms.gateway_offline","sms.gateway_online","ai.draft_ready","ai.responded","ai.escalated"]}},"is_active":{"type":"boolean"},"smtp_account_id":{"type":"string","format":"uuid","nullable":true,"description":"If set, this webhook only fires for events from this SMTP account. Null = org-wide."},"whatsapp_account_id":{"type":"string","format":"uuid","nullable":true,"description":"If set, this webhook only fires for events from this WhatsApp account. Null = org-wide."},"sms_gateway_id":{"type":"string","format":"uuid","nullable":true,"description":"If set, this webhook only fires for events from this SMS gateway. Null = org-wide."},"created_at":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}},"delete":{"summary":"Delete webhook","tags":["Webhooks"],"description":"Permanently delete a webhook configuration. Requires `webhooks.write` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/webhooks/{id}/deliveries":{"get":{"summary":"Get webhook deliveries","tags":["Webhooks"],"description":"Retrieve delivery history for a specific webhook. Requires `webhooks.read` permission.","parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"in":"query","name":"per_page","required":false},{"schema":{"type":"string"},"in":"query","name":"status","required":false,"description":"Filter by delivery status (pending, success, failed)"},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"event_type":{"type":"string"},"status":{"type":"string"},"response_code":{"type":"integer","nullable":true},"attempts":{"type":"integer"},"created_at":{"type":"string","format":"date-time"}}}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/whatsapp/send":{"post":{"summary":"Send WhatsApp message","tags":["WhatsApp"],"description":"Send a single WhatsApp message (text, image, video, audio, document, etc.). Requires `whatsapp` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to"],"properties":{"to":{"type":"string","description":"Recipient — either an E.164 phone (e.g. +32471234567) for a private chat, or a WhatsApp group JID (e.g. 120363195577337777@g.us) to post in a group. The bare group id without \"@g.us\" is also accepted."},"type":{"type":"string","enum":["text","image","video","audio","document","sticker","contact","location"],"default":"text"},"body":{"type":"string","description":"Text message body (required for type=text)"},"media_url":{"type":"string","format":"uri","description":"Media URL (for image/video/audio/document types). Must be a direct URL (no redirects)."},"media_caption":{"type":"string","maxLength":1024,"description":"Caption for media messages"},"latitude":{"type":"number","description":"Latitude (required for type=location)"},"longitude":{"type":"number","description":"Longitude (required for type=location)"},"location_name":{"type":"string","description":"Location name (optional for type=location)"},"contact_name":{"type":"string","description":"Contact name (required for type=contact)"},"contact_phone":{"type":"string","description":"Contact phone (required for type=contact)"},"scheduled_at":{"type":"string","format":"date-time","description":"Schedule send time (ISO 8601)"},"whatsapp_account_id":{"type":"string","format":"uuid","description":"Specific WhatsApp account to use (uses first active if omitted)"}}},"examples":{"example1":{"value":{"summary":"Text","value":{"to":"+32470123456","type":"text","body":"Hello from Sendy!"}}},"example2":{"value":{"summary":"Image","value":{"to":"+32470123456","type":"image","media_url":"https://example.com/photo.jpg","media_caption":"A photo"}}},"example3":{"value":{"summary":"Document","value":{"to":"+32470123456","type":"document","media_url":"https://example.com/report.pdf","media_caption":"Report"}}},"example4":{"value":{"summary":"Location","value":{"to":"+32470123456","type":"location","latitude":50.8503,"longitude":4.3517,"location_name":"Brussels"}}},"example5":{"value":{"summary":"Contact","value":{"to":"+32470123456","type":"contact","contact_name":"John Doe","contact_phone":"+32471234567"}}},"example6":{"value":{"summary":"Group text","value":{"to":"120363195577337777@g.us","type":"text","body":"Hello team!"}}}}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["QUEUED"]},"to":{"type":"string"},"scheduled_at":{"type":"string","format":"date-time","nullable":true}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/whatsapp/send-batch":{"post":{"summary":"Batch send WhatsApp messages","tags":["WhatsApp"],"description":"Send WhatsApp messages to multiple recipients (max 500). Supports variable replacement. Requires `whatsapp` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["recipients"],"properties":{"recipients":{"type":"array","minItems":1,"maxItems":500,"items":{"type":"object","required":["to"],"properties":{"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"E.164 phone number"},"variables":{"type":"object","additionalProperties":{"type":"string"},"description":"Template variables for {{key}} replacement"}}}},"body":{"type":"string","description":"Text body (supports {{variable}} placeholders)"},"whatsapp_account_id":{"type":"string","format":"uuid"}},"example":{"recipients":[{"to":"+32470123456","variables":{"name":"Alice"}},{"to":"+32470654321","variables":{"name":"Bob"}}],"type":"text","body":"Hello {{name}}!"}}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"to":{"type":"string"},"status":{"type":"string","enum":["QUEUED"]}}}},"meta":{"type":"object","properties":{"total":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/whatsapp/messages":{"get":{"summary":"List WhatsApp messages","tags":["WhatsApp"],"description":"Retrieve a paginated list of WhatsApp messages with optional filters. Requires `whatsapp` permission.","parameters":[{"schema":{"type":"string"},"in":"query","name":"status","required":false,"description":"Filter by status (QUEUED, SENT, DELIVERED, READ, FAILED)"},{"schema":{"type":"string","enum":["OUTBOUND","INBOUND"]},"in":"query","name":"direction","required":false,"description":"Filter by message direction"},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"date_from","required":false,"description":"Filter from date (ISO 8601)"},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"date_to","required":false,"description":"Filter to date (ISO 8601)"},{"schema":{"type":"string"},"in":"query","name":"to","required":false,"description":"Filter by recipient (partial match)"},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"per_page","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"whatsapp_account_id","required":false,"description":"Filter by specific WhatsApp account"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["OUTBOUND","INBOUND"]},"to":{"type":"string"},"from":{"type":"string","description":"For inbound group messages this is the group id; the real participant who posted is in `senderJid`."},"senderJid":{"type":"string","nullable":true,"description":"Full WhatsApp JID of the actual sender (for inbound). For groups, this is the participant; for 1-to-1 chats, the contact JID."},"senderPushName":{"type":"string","nullable":true,"description":"Push (display) name of the sender at the time of the message."},"body":{"type":"string","nullable":true},"mediaType":{"type":"string","nullable":true},"status":{"type":"string"},"providerUsed":{"type":"string","nullable":true},"sentAt":{"type":"string","format":"date-time","nullable":true},"deliveredAt":{"type":"string","format":"date-time","nullable":true},"readAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"failureReason":{"type":"string","nullable":true}}}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/whatsapp/messages/{id}":{"get":{"summary":"Get WhatsApp message","tags":["WhatsApp"],"description":"Retrieve a single WhatsApp message with account and conversation details. Requires `whatsapp` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["OUTBOUND","INBOUND"]},"to":{"type":"string"},"from":{"type":"string","description":"For inbound group messages this is the group id; the real participant is in `senderJid`."},"senderJid":{"type":"string","nullable":true},"senderPushName":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"mediaType":{"type":"string","nullable":true},"mediaUrl":{"type":"string","nullable":true},"mediaCaption":{"type":"string","nullable":true},"status":{"type":"string"},"providerUsed":{"type":"string","nullable":true},"sentAt":{"type":"string","format":"date-time","nullable":true},"deliveredAt":{"type":"string","format":"date-time","nullable":true},"readAt":{"type":"string","format":"date-time","nullable":true},"failureReason":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"whatsappAccount":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"phoneNumber":{"type":"string"}}},"conversation":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"contactPhone":{"type":"string"},"contactName":{"type":"string","nullable":true}}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/whatsapp/conversations":{"get":{"summary":"List conversations","tags":["WhatsApp"],"description":"Retrieve a paginated list of WhatsApp conversations. Requires `whatsapp` permission.","parameters":[{"schema":{"type":"string","enum":["ACTIVE","ARCHIVED","BLOCKED"]},"in":"query","name":"status","required":false,"description":"Filter by conversation status"},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"per_page","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"whatsapp_account_id","required":false,"description":"Filter by specific WhatsApp account"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"contactPhone":{"type":"string"},"contactName":{"type":"string","nullable":true},"contactPushName":{"type":"string","nullable":true},"isGroup":{"type":"boolean","description":"True if this conversation is a WhatsApp group. For groups, `contactPhone` is the bare group id (no \"@g.us\" suffix)."},"memberCount":{"type":"integer","nullable":true,"description":"Number of members in the group (null for 1-to-1 conversations)."},"lastMessageAt":{"type":"string","format":"date-time","nullable":true},"lastMessagePreview":{"type":"string","nullable":true},"unreadCount":{"type":"integer"},"status":{"type":"string","enum":["ACTIVE","ARCHIVED","BLOCKED"]},"windowExpiresAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}}}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/whatsapp/conversations/{id}":{"get":{"summary":"Get conversation with messages","tags":["WhatsApp"],"description":"Retrieve a single WhatsApp conversation with its last 50 messages. Requires `whatsapp` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"contactPhone":{"type":"string"},"contactName":{"type":"string","nullable":true},"contactPushName":{"type":"string","nullable":true},"lastMessageAt":{"type":"string","format":"date-time","nullable":true},"lastMessagePreview":{"type":"string","nullable":true},"unreadCount":{"type":"integer"},"status":{"type":"string"},"windowExpiresAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["OUTBOUND","INBOUND"]},"to":{"type":"string"},"from":{"type":"string"},"senderJid":{"type":"string","nullable":true},"senderPushName":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"mediaType":{"type":"string","nullable":true},"mediaUrl":{"type":"string","nullable":true},"mediaCaption":{"type":"string","nullable":true},"status":{"type":"string"},"providerUsed":{"type":"string","nullable":true},"sentAt":{"type":"string","format":"date-time","nullable":true},"deliveredAt":{"type":"string","format":"date-time","nullable":true},"readAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}}}},"whatsappAccount":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"phoneNumber":{"type":"string"}}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/whatsapp/groups":{"get":{"summary":"List WhatsApp groups","tags":["WhatsApp"],"description":"List all WhatsApp groups the configured account is a member of (live data from Sendy Gate). Requires `whatsapp` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"whatsapp_account_id","required":false,"description":"Use a specific WhatsApp account (defaults to first active)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"jid":{"type":"string","description":"Full WhatsApp JID, e.g. \"120363xxxxx@g.us\" — use this as `to` in /whatsapp/send to post in the group"},"id":{"type":"string","description":"Bare group id (no \"@g.us\" suffix)"},"name":{"type":"string"},"memberCount":{"type":"integer"}}}},"meta":{"type":"object","properties":{"total":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/whatsapp/groups/{group_jid}":{"get":{"summary":"Get WhatsApp group details","tags":["WhatsApp"],"description":"Get full info for a group (name, topic, owner, participants count). Accepts either the full JID (\"120363xxx@g.us\") or just the bare id. Requires `whatsapp` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"whatsapp_account_id","required":false},{"schema":{"type":"string"},"in":"path","name":"group_jid","required":true,"description":"WhatsApp group JID or bare id"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"jid":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"topic":{"type":"string","nullable":true},"ownerJid":{"type":"string","nullable":true},"isAnnounce":{"type":"boolean","description":"True if only admins can post"},"isLocked":{"type":"boolean"},"createdAt":{"type":"string","nullable":true},"memberCount":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/whatsapp/groups/{group_jid}/participants":{"get":{"summary":"List group participants","tags":["WhatsApp"],"description":"List all members of a WhatsApp group, including their admin role. Requires `whatsapp` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"whatsapp_account_id","required":false},{"schema":{"type":"string"},"in":"path","name":"group_jid","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"jid":{"type":"string"},"phone":{"type":"string","description":"Phone digits without \"@s.whatsapp.net\""},"isAdmin":{"type":"boolean"},"isSuperAdmin":{"type":"boolean"}}}},"meta":{"type":"object","properties":{"total":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/whatsapp/messages/{id}/cancel":{"delete":{"summary":"Cancel WhatsApp message","tags":["WhatsApp"],"description":"Cancel a queued WhatsApp message before it is sent. Only messages with status QUEUED can be cancelled. Requires `whatsapp` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["CANCELLED"]},"cancelled":{"type":"boolean","enum":[true]},"queue_removed":{"type":"boolean","description":"Whether the job was removed from the processing queue"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/whatsapp/accounts/{id}/sync":{"post":{"summary":"Force re-sync of WhatsApp account from GOWA","tags":["WhatsApp"],"description":"Re-pulls chats and groups from Sendy Gate into the database. Useful to surface newly-created groups without waiting for the periodic sync. Rate-limited to 1 call / 30s per account. Requires `whatsapp` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"conversations":{"type":"integer","description":"Number of conversations touched (created or updated)"},"imported":{"type":"integer","description":"Number of new messages imported"},"skipped":{"type":"integer","description":"Number of messages skipped (already in DB)"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"429":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/whatsapp/check-number":{"post":{"summary":"Check WhatsApp number","tags":["WhatsApp"],"description":"Check if a phone number is registered on WhatsApp. Requires `whatsapp.send` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["number"],"properties":{"number":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"Phone number in E.164 format"},"whatsapp_account_id":{"type":"string","format":"uuid","description":"Specific WhatsApp account to use (optional, defaults to first active)"}}},"example":{"summary":"Check number","value":{"number":"+32470123456"}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"number":{"type":"string"},"registered":{"type":"boolean"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"503":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/ai/conversations":{"get":{"summary":"List AI conversations","tags":["AI"],"description":"Retrieve a paginated list of AI conversations with optional filters by channel and status. Requires `ai` permission.","parameters":[{"schema":{"type":"string","enum":["EMAIL","WHATSAPP"]},"in":"query","name":"channel","required":false,"description":"Filter by conversation channel"},{"schema":{"type":"string","enum":["ACTIVE","ARCHIVED","BLOCKED"]},"in":"query","name":"status","required":false,"description":"Filter by conversation status"},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"agent_id","required":false,"description":"Filter by specific AI agent"},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"per_page","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"channel":{"type":"string","enum":["EMAIL","WHATSAPP"]},"contactIdentifier":{"type":"string"},"contactName":{"type":"string","nullable":true},"status":{"type":"string","enum":["ACTIVE","ARCHIVED","BLOCKED"]},"humanTakeover":{"type":"boolean"},"unreadCount":{"type":"integer"},"lastMessageAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"agent":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"lastMessage":{"type":"object","nullable":true,"properties":{"content":{"type":"string"},"direction":{"type":"string","enum":["INBOUND","OUTBOUND"]},"status":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"messageCount":{"type":"integer"}}}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/ai/conversations/{id}":{"get":{"summary":"Get AI conversation detail","tags":["AI"],"description":"Retrieve a single AI conversation with its last 50 messages and agent info. Requires `ai` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"channel":{"type":"string","enum":["EMAIL","WHATSAPP"]},"contactIdentifier":{"type":"string"},"contactName":{"type":"string","nullable":true},"status":{"type":"string","enum":["ACTIVE","ARCHIVED","BLOCKED"]},"humanTakeover":{"type":"boolean"},"unreadCount":{"type":"integer"},"lastMessageAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"agent":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"responseMode":{"type":"string","enum":["DRAFT","AUTO_REPLY"]}}},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["INBOUND","OUTBOUND"]},"content":{"type":"string"},"status":{"type":"string"},"confidenceScore":{"type":"integer","nullable":true},"sentiment":{"type":"string","nullable":true},"category":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}}}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/ai/conversations/{id}/messages":{"get":{"summary":"Get conversation messages","tags":["AI"],"description":"Retrieve paginated messages for an AI conversation with AI trace data (classification, tools, reasoning). Requires `ai` permission.","parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"per_page","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["INBOUND","OUTBOUND"]},"content":{"type":"string"},"contentHtml":{"type":"string","nullable":true},"status":{"type":"string"},"confidenceScore":{"type":"integer","nullable":true},"reasoning":{"type":"string","nullable":true},"modelUsed":{"type":"string","nullable":true},"inputTokens":{"type":"integer","nullable":true},"outputTokens":{"type":"integer","nullable":true},"costCents":{"type":"integer","nullable":true},"toolCallsCount":{"type":"integer","nullable":true},"toolCallsLog":{"type":"object","nullable":true},"processingTimeMs":{"type":"integer","nullable":true},"sentiment":{"type":"string","nullable":true},"sentimentScore":{"type":"integer","nullable":true},"category":{"type":"string","nullable":true},"urgency":{"type":"string","nullable":true},"complexity":{"type":"string","nullable":true},"autoTags":{"type":"object","nullable":true},"createdAt":{"type":"string","format":"date-time"}}}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/ai/drafts/{id}/approve":{"post":{"summary":"Approve draft message","tags":["AI"],"description":"Approve an AI draft message and dispatch it for sending. Only messages with status DRAFT can be approved. Requires `ai` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["OUTBOUND"]},"content":{"type":"string"},"status":{"type":"string","enum":["APPROVED"]},"conversationId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/ai/drafts/{id}/edit":{"post":{"summary":"Edit and approve draft message","tags":["AI"],"description":"Edit the content of an AI draft message, approve it, and dispatch for sending. Creates a correction record for agent learning. Requires `ai` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["content"],"properties":{"content":{"type":"string","minLength":1,"maxLength":10000,"description":"The corrected message content"}},"example":{"content":"Thank you for reaching out! I have updated your order status."}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["OUTBOUND"]},"content":{"type":"string"},"status":{"type":"string","enum":["APPROVED"]},"conversationId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/ai/conversations/{id}/reply":{"post":{"summary":"Send manual reply","tags":["AI"],"description":"Send a manual reply in an AI conversation. Creates an outbound message with APPROVED status and dispatches it for sending. Requires `ai` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["content"],"properties":{"content":{"type":"string","minLength":1,"maxLength":5000,"description":"The reply message content"}},"example":{"content":"Let me check that for you and get back shortly."}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["OUTBOUND"]},"content":{"type":"string"},"status":{"type":"string","enum":["APPROVED"]},"conversationId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/ai/agents":{"get":{"summary":"List AI agents","tags":["AI"],"description":"Retrieve a paginated list of active AI agents with model info and conversation count. Requires `ai` permission.","parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"per_page","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"responseMode":{"type":"string","enum":["DRAFT","AUTO_REPLY"]},"isActive":{"type":"boolean"},"humanTakeover":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"model":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"modelId":{"type":"string"},"provider":{"type":"string"}}},"conversationCount":{"type":"integer"}}}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/ai/usage":{"get":{"summary":"Get AI usage stats","tags":["AI"],"description":"Retrieve AI usage statistics for a given month (defaults to current month). Includes message counts, token usage, and estimated cost. Requires `ai` permission.","parameters":[{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}$"},"in":"query","name":"period","required":false,"description":"Month in YYYY-MM format (defaults to current month)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"period":{"type":"string","description":"Month period in YYYY-MM format"},"totalMessages":{"type":"integer","description":"Total AI messages processed"},"inboundMessages":{"type":"integer","description":"Messages received from contacts"},"outboundMessages":{"type":"integer","description":"Messages sent (auto-reply + approved drafts)"},"draftMessages":{"type":"integer","description":"Messages currently in draft status"},"autoReplies":{"type":"integer","description":"Messages auto-replied by AI"},"totalInputTokens":{"type":"integer","description":"Total input tokens consumed"},"totalOutputTokens":{"type":"integer","description":"Total output tokens consumed"},"totalCostCents":{"type":"integer","description":"Total estimated cost in cents"},"activeConversations":{"type":"integer","description":"Conversations with activity in this period"},"activeAgents":{"type":"integer","description":"Agents that processed messages in this period"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/sms/gateways":{"get":{"summary":"List SMS gateways","tags":["SMS"],"description":"List all SMS gateways for the organization. Requires `sms` permission.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"phoneNumber":{"type":"string"},"status":{"type":"string","enum":["ONLINE","OFFLINE"]},"simSlots":{"type":"integer"},"isActive":{"type":"boolean"},"lastSeenAt":{"type":"string","format":"date-time","nullable":true}}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/sms/send":{"post":{"summary":"Send SMS message","tags":["SMS"],"description":"Send a single SMS message. The message is queued and picked up by the phone gateway. Requires `sms` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to","body"],"properties":{"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"Recipient phone number in E.164 format (e.g. +32470123456)"},"body":{"type":"string","minLength":1,"maxLength":1600,"description":"SMS message body (max 1600 chars)"},"gateway_id":{"type":"string","format":"uuid","description":"Specific SMS gateway to use (uses first active if omitted)"},"scheduled_at":{"type":"string","format":"date-time","description":"Schedule send time (ISO 8601). Must be in the future. Omit to send immediately."}},"example":{"to":"+32470123456","body":"Your verification code is 123456"}}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["QUEUED"]},"to":{"type":"string"},"scheduled_at":{"type":"string","format":"date-time","nullable":true,"description":"Scheduled send time (ISO 8601), or null for immediate send"},"costCents":{"type":"integer","description":"Cost charged to caller for this SMS (0 for own/included)"},"billedFrom":{"type":"string","enum":["FREE","INCLUDED","CREDIT","POSTPAID"],"description":"Billing source: FREE=own gateway, INCLUDED=plan quota, CREDIT=wallet debit, POSTPAID=invoiced monthly"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"402":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/sms/send/batch":{"post":{"summary":"Batch send SMS messages","tags":["SMS"],"description":"Send SMS messages to multiple recipients (max 500). Each message can have its own body. Requires `sms` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","minItems":1,"maxItems":500,"items":{"type":"object","required":["to","body"],"properties":{"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"E.164 phone number"},"body":{"type":"string","minLength":1,"maxLength":1600,"description":"SMS message body"}}}},"gateway_id":{"type":"string","format":"uuid","description":"Specific SMS gateway to use (uses first active if omitted)"},"scheduled_at":{"type":"string","format":"date-time","description":"Schedule send time (ISO 8601) applied to every message in the batch. Must be in the future."}},"example":{"messages":[{"to":"+32470123456","body":"Flash sale! 20% off today."},{"to":"+32470654321","body":"Flash sale! 20% off today."}]}}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","nullable":true},"to":{"type":"string"},"status":{"type":"string","enum":["QUEUED","FAILED"]},"costCents":{"type":"integer","nullable":true,"description":"Cost charged for this SMS (0 for own/included)"},"billedFrom":{"type":"string","enum":["FREE","INCLUDED","CREDIT","POSTPAID"],"nullable":true,"description":"Billing source"},"error":{"type":"string","nullable":true,"description":"Error code when status=FAILED"}}}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"sentCount":{"type":"integer"},"failedCount":{"type":"integer"},"totalCostCents":{"type":"integer"},"partialSuccess":{"type":"boolean"},"firstFailureIndex":{"type":"integer","nullable":true},"billedFromBreakdown":{"type":"object","properties":{"FREE":{"type":"integer"},"INCLUDED":{"type":"integer"},"CREDIT":{"type":"integer"},"POSTPAID":{"type":"integer"}}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"402":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}},"meta":{"type":"object","properties":{"required":{"type":"integer"},"available":{"type":"integer"},"missing":{"type":"integer"}}}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/sms/messages":{"get":{"summary":"List SMS messages","tags":["SMS"],"description":"Retrieve a paginated list of SMS messages with optional filters. Requires `sms` permission.","parameters":[{"schema":{"type":"string","enum":["QUEUED","PENDING","SENT","DELIVERED","FAILED"]},"in":"query","name":"status","required":false,"description":"Filter by status"},{"schema":{"type":"string","enum":["OUTBOUND","INBOUND"]},"in":"query","name":"direction","required":false,"description":"Filter by message direction"},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"gateway_id","required":false,"description":"Filter by specific SMS gateway"},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"date_from","required":false,"description":"Filter from date (ISO 8601)"},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"date_to","required":false,"description":"Filter to date (ISO 8601)"},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"per_page","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["OUTBOUND","INBOUND"]},"from":{"type":"string"},"to":{"type":"string"},"body":{"type":"string"},"simSlot":{"type":"integer","nullable":true},"status":{"type":"string"},"errorMessage":{"type":"string","nullable":true},"sentAt":{"type":"string","format":"date-time","nullable":true},"deliveredAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}}}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/sms/messages/{id}":{"get":{"summary":"Get SMS message","tags":["SMS"],"description":"Retrieve a single SMS message with gateway and conversation details. Requires `sms` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["OUTBOUND","INBOUND"]},"from":{"type":"string"},"to":{"type":"string"},"body":{"type":"string"},"simSlot":{"type":"integer","nullable":true},"status":{"type":"string"},"errorMessage":{"type":"string","nullable":true},"scheduledAt":{"type":"string","format":"date-time","nullable":true},"sentAt":{"type":"string","format":"date-time","nullable":true},"deliveredAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"gateway":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"phoneNumber":{"type":"string"}}},"conversation":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"contactPhone":{"type":"string"}}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/sms/messages/{id}/cancel":{"delete":{"summary":"Cancel SMS message","tags":["SMS"],"description":"Cancel a queued/scheduled SMS before it is sent. Only messages with status QUEUED can be cancelled. Requires `sms` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["CANCELLED"]},"cancelled":{"type":"boolean","enum":[true]}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/contacts":{"get":{"summary":"List contacts","tags":["Contacts"],"description":"Retrieve a paginated list of contacts with optional search and source filter. Requires `contacts.read` permission.","parameters":[{"schema":{"type":"string"},"in":"query","name":"search","required":false,"description":"Search by name, email, or phone number"},{"schema":{"type":"string","enum":["MANUAL","WHATSAPP","EMAIL","SMS","CSV","API"]},"in":"query","name":"source","required":false,"description":"Filter by contact source"},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"per_page","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"company":{"type":"string","nullable":true},"avatarUrl":{"type":"string","nullable":true},"source":{"type":"string","enum":["MANUAL","WHATSAPP","EMAIL","SMS","CSV","API"]},"engagementScore":{"type":"integer"},"lastSeenAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}},"post":{"summary":"Create contact","tags":["Contacts"],"description":"Create a new contact. At least one of `email` or `phone` is recommended. Requires `contacts.write` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"Contact email address"},"phone":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"Phone number in E.164 format"},"firstName":{"type":"string","maxLength":255,"description":"First name"},"lastName":{"type":"string","maxLength":255,"description":"Last name"},"company":{"type":"string","maxLength":255,"description":"Company name"},"source":{"type":"string","enum":["MANUAL","WHATSAPP","EMAIL","SMS","CSV","API"],"default":"API","description":"How the contact was acquired"},"metadata":{"type":"object","description":"Arbitrary key-value metadata","additionalProperties":true}},"example":{"email":"john@example.com","firstName":"John","lastName":"Doe","phone":"+32470123456","source":"API"}}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"company":{"type":"string","nullable":true},"avatarUrl":{"type":"string","nullable":true},"source":{"type":"string","enum":["MANUAL","WHATSAPP","EMAIL","SMS","CSV","API"]},"engagementScore":{"type":"integer"},"lastSeenAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/contacts/tags":{"get":{"summary":"List tags","tags":["Contacts"],"description":"List all tags for the organization. Requires `contacts.read` permission.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"color":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/contacts/lists":{"get":{"summary":"List contact lists","tags":["Contacts"],"description":"List all contact lists for the organization with member counts. Requires `contacts.read` permission.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"memberCount":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/contacts/{id}":{"get":{"summary":"Get contact","tags":["Contacts"],"description":"Retrieve a single contact with tags. Requires `contacts.read` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"company":{"type":"string","nullable":true},"avatarUrl":{"type":"string","nullable":true},"source":{"type":"string","enum":["MANUAL","WHATSAPP","EMAIL","SMS","CSV","API"]},"engagementScore":{"type":"integer"},"lastSeenAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}},"patch":{"summary":"Update contact","tags":["Contacts"],"description":"Update one or more fields on a contact. Only provided fields are updated. Requires `contacts.write` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email","nullable":true,"description":"Contact email address"},"phone":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","nullable":true,"description":"Phone number in E.164 format"},"firstName":{"type":"string","maxLength":255,"nullable":true,"description":"First name"},"lastName":{"type":"string","maxLength":255,"nullable":true,"description":"Last name"},"company":{"type":"string","maxLength":255,"nullable":true,"description":"Company name"}},"example":{"firstName":"Jane","company":"Acme Corp"}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"company":{"type":"string","nullable":true},"avatarUrl":{"type":"string","nullable":true},"source":{"type":"string","enum":["MANUAL","WHATSAPP","EMAIL","SMS","CSV","API"]},"engagementScore":{"type":"integer"},"lastSeenAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}},"delete":{"summary":"Delete contact","tags":["Contacts"],"description":"Permanently delete a contact and all associated data. Requires `contacts.write` permission.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"deleted":{"type":"boolean","enum":[true]}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/otp/send":{"post":{"summary":"Send OTP code","tags":["OTP"],"description":"Generate and send a 6-digit verification code via SMS, WhatsApp, or Email. Rate limited to 5 per hour per recipient. Requires `verify.use` permission.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to","channel"],"properties":{"to":{"type":"string","description":"Recipient: E.164 phone for SMS/WhatsApp, email address for email"},"channel":{"type":"string","enum":["sms","whatsapp","email"],"description":"Delivery channel"},"brand_name":{"type":"string","maxLength":50,"description":"Brand name in the message (default: \"Sendy\")"},"locale":{"type":"string","enum":["en","fr"],"description":"Message language (default: \"en\")"},"reference":{"type":"string","maxLength":255,"description":"Free-form metadata returned on verification"}},"example":{"to":"+32470123456","channel":"sms","brand_name":"MyApp","reference":"signup-user-42"}}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"otp_id":{"type":"string","format":"uuid"},"channel":{"type":"string"},"to":{"type":"string","description":"Masked recipient"},"expires_at":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["sent"]}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"429":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}},"/api/v1/otp/verify":{"post":{"summary":"Verify OTP code","tags":["OTP"],"description":"Verify a previously sent OTP code. Returns valid: true on match, valid: false with remaining attempts on mismatch. Max 3 attempts.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["otp_id","code"],"properties":{"otp_id":{"type":"string","format":"uuid","description":"OTP ID returned by /otp/send"},"code":{"type":"string","pattern":"^\\d{6}$","description":"6-digit verification code"}},"example":{"otp_id":"550e8400-e29b-41d4-a716-446655440000","code":"482917"}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"valid":{"type":"boolean"},"reference":{"type":"string","nullable":true},"attempts_remaining":{"type":"integer"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"410":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"429":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}}}}},"servers":[{"url":"https://sendy.cloud","description":"API Server"}],"tags":[{"name":"Emails","description":"Send, schedule, list, and cancel transactional emails via your connected SMTP accounts."},{"name":"Tracking","description":"Retrieve open/click tracking events and aggregate email statistics."},{"name":"Inbox","description":"Read and manage inbound emails received via IMAP."},{"name":"Suppressions","description":"Manage the per-account suppression list (bounces, unsubscribes, manual blocks)."},{"name":"Webhooks","description":"Configure webhook endpoints to receive real-time event notifications (email.sent, email.bounced, etc.)."},{"name":"Verification","description":"Validate email addresses (syntax, MX records, disposable domain detection)."},{"name":"WhatsApp","description":"Send and receive WhatsApp messages via Sendy Gate. Supports text, media, batch send, conversations, and scheduling. Requires `whatsapp.send` or `whatsapp.history` permission."},{"name":"SMS","description":"Send SMS messages via Android phone gateways."},{"name":"AI","description":"AI-powered conversations: view drafts, approve/edit responses, and monitor usage."},{"name":"Contacts","description":"Manage contacts, tags, and contact lists."},{"name":"OTP","description":"Generate and verify one-time passwords via SMS, WhatsApp, or Email. Requires `verify.use` permission."}]}