{ "openapi": "3.0.3", "info": { "title": "Notifuse API", "description": "API for Notifuse - a transactional email and newsletter management platform", "version": "1.0.0", "contact": { "name": "Notifuse Support", "url": "https://www.notifuse.com/support", "email": "hello@notifuse.com" } }, "servers": [ { "url": "https://{notifuseDomain}", "description": "Customer-specific Notifuse API server", "variables": { "notifuseDomain": { "description": "Your unique Notifuse domain", "default": "demo.notifuse.com" } } } ], "paths": { "/api/transactional.send": { "post": { "summary": "Send a transactional notification", "description": "Sends a transactional notification to a contact through specified channels.\nRequires authentication.\n", "operationId": "sendTransactionalNotification", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendTransactionalRequest" } } } }, "responses": { "200": { "description": "Notification sent successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "message_id": { "type": "string", "description": "Unique identifier for the sent message", "example": "msg_1234567890abcdef" }, "success": { "type": "boolean", "description": "Whether the notification was sent successfully", "example": true } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "notFoundExample": { "value": { "error": "Notification not found" } }, "inactiveExample": { "value": { "error": "Notification is not active" } }, "noChannelsExample": { "value": { "error": "No valid channels configured" } }, "validationExample": { "value": { "error": "notification.contact is required" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Unauthorized" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Failed to send notification" } } } } } } }, "/api/contacts.list": { "get": { "summary": "List contacts with filtering and pagination", "description": "Retrieves a paginated list of contacts with optional filtering. All contact fields are always returned.\n\n**Filtering**: Use filters to search for contacts. Text filters (email, external_id, first_name, last_name, full_name, phone, country, language) use case-insensitive partial matching (ILIKE).\n\n**List filtering**: Use `list_id` and/or `contact_list_status` to filter contacts by list membership.\n\n**Segment filtering**: Use `segments[]` to filter contacts that belong to specific segments.\n\n**Contact lists**: By default, `contact_lists` is not included in the response. Set `with_contact_lists=true` to include the contact's list subscriptions.\n\n**Pagination**: Uses cursor-based pagination. Use the `next_cursor` from the response to fetch the next page.\n", "operationId": "listContacts", "security": [ { "BearerAuth": [] } ], "parameters": [ { "name": "workspace_id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The ID of the workspace", "example": "ws_1234567890" }, { "name": "email", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Filter by email (case-insensitive partial match)", "example": "user@example" }, { "name": "external_id", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Filter by external ID (case-insensitive partial match)", "example": "user_123" }, { "name": "first_name", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Filter by first name (case-insensitive partial match)", "example": "John" }, { "name": "last_name", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Filter by last name (case-insensitive partial match)", "example": "Doe" }, { "name": "full_name", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Filter by full name (case-insensitive partial match)", "example": "John Doe" }, { "name": "phone", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Filter by phone number (case-insensitive partial match)", "example": "+1555" }, { "name": "country", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Filter by country (case-insensitive partial match)", "example": "US" }, { "name": "language", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Filter by language (case-insensitive partial match)", "example": "en" }, { "name": "list_id", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Filter by list membership (contacts subscribed to this list)", "example": "newsletter" }, { "name": "contact_list_status", "in": "query", "required": false, "schema": { "type": "string", "enum": [ "active", "pending", "unsubscribed", "bounced", "complained" ] }, "description": "Filter by subscription status within the list", "example": "active" }, { "name": "segments[]", "in": "query", "required": false, "schema": { "type": "array", "items": { "type": "string" } }, "description": "Filter by segment membership (contacts in any of these segments)", "example": [ "premium_users", "active_buyers" ] }, { "name": "with_contact_lists", "in": "query", "required": false, "schema": { "type": "boolean", "default": false }, "description": "Include contact list subscriptions in the response", "example": true }, { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }, "description": "Maximum number of contacts to return (1-100)", "example": 50 }, { "name": "cursor", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Pagination cursor from previous response", "example": "MjAyMy0wMS0xNVQxMDozMDowMFp+dXNlckBleGFtcGxlLmNvbQ==" } ], "responses": { "200": { "description": "Contacts retrieved successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListContactsResponse" } } } }, "400": { "description": "Bad request - invalid parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "workspace_id is required" } }, "invalidLimit": { "value": { "error": "limit must be between 1 and 100" } }, "invalidCursor": { "value": { "error": "invalid cursor encoding" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/contacts.count": { "get": { "summary": "Count contacts in a workspace", "description": "Returns the total number of contacts in a workspace.", "operationId": "countContacts", "security": [ { "BearerAuth": [] } ], "parameters": [ { "name": "workspace_id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The ID of the workspace", "example": "ws_1234567890" } ], "responses": { "200": { "description": "Contact count retrieved successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CountContactsResponse" } } } }, "400": { "description": "Bad request - missing workspace ID", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Missing workspace ID" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/contacts.upsert": { "post": { "summary": "Create or update a contact", "description": "Creates a new contact or updates an existing one. Contacts are matched **by email address only** — the email is the contact's unique identifier. `external_id` is stored but never used for matching, so sending an existing `external_id` with a new email address creates a second contact.\n\nTo change a contact's email address: upsert a contact with the new email and the full profile, re-create its list subscriptions (preserving unsubscribed/bounced/complained statuses — do not reset opt-outs), then delete the contact with the old email using `contacts.delete`. Message history and segment memberships are keyed to the email address and are not transferred.\n\nReturns information about whether the contact was created or updated.\n", "operationId": "upsertContact", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpsertContactRequest" } } } }, "responses": { "200": { "description": "Contact upserted successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpsertContactResponse" } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "workspace_id is required" } }, "invalidEmail": { "value": { "error": "invalid email format" } }, "missingContact": { "value": { "error": "contact is required" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/contacts.getByEmail": { "get": { "summary": "Get a contact by email address", "description": "Retrieves a contact by their email address within a specific workspace. The response always includes the contact's list subscriptions with their status (active, pending, unsubscribed, bounced, complained).", "operationId": "getContactByEmail", "security": [ { "BearerAuth": [] } ], "parameters": [ { "name": "workspace_id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The ID of the workspace", "example": "ws_1234567890" }, { "name": "email", "in": "query", "required": true, "schema": { "type": "string", "format": "email" }, "description": "The email address of the contact", "example": "user@example.com" } ], "responses": { "200": { "description": "Contact found successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "contact": { "$ref": "#/components/schemas/Contact" } } } } } }, "400": { "description": "Bad request - missing parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "Missing workspace ID" } }, "missingEmail": { "value": { "error": "Missing email" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Contact not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Contact not found" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/contacts.getByExternalID": { "get": { "summary": "Get a contact by external ID", "description": "Retrieves a contact by their external ID within a specific workspace. The response always includes the contact's list subscriptions with their status (active, pending, unsubscribed, bounced, complained).\n\nNote that `external_id` is not unique — if several contacts share the same external ID, only one of them is returned (which one is not defined). Contacts are uniquely identified by email address.\n", "operationId": "getContactByExternalID", "security": [ { "BearerAuth": [] } ], "parameters": [ { "name": "workspace_id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The ID of the workspace", "example": "ws_1234567890" }, { "name": "external_id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The external ID of the contact", "example": "user_12345" } ], "responses": { "200": { "description": "Contact found successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "contact": { "$ref": "#/components/schemas/Contact" } } } } } }, "400": { "description": "Bad request - missing parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "Missing workspace ID" } }, "missingExternalId": { "value": { "error": "Missing external ID" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Contact not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Contact not found" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/contacts.import": { "post": { "summary": "Batch import contacts", "description": "Creates or updates multiple contacts in a single batch operation. This is significantly more efficient than individual upsert operations. Optionally subscribes all contacts to specified lists.", "operationId": "batchImportContacts", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BatchImportContactsRequest" } } } }, "responses": { "200": { "description": "Batch import completed (may include partial failures)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BatchImportContactsResponse" } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "workspace_id is required" } }, "missingContacts": { "value": { "error": "contacts is required" } }, "emptyContacts": { "value": { "error": "contacts array cannot be empty" } }, "insufficientPermissions": { "value": { "error": "write access to lists required when subscribe_to_lists is provided" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/contacts.delete": { "post": { "summary": "Delete a contact", "description": "Deletes a contact from the workspace by email address. This action is permanent and cannot be undone.", "operationId": "deleteContact", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteContactRequest" } } } }, "responses": { "200": { "description": "Contact deleted successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the deletion was successful", "example": true } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "workspace_id is required" } }, "missingEmail": { "value": { "error": "email is required" } }, "invalidEmail": { "value": { "error": "invalid email format" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Contact not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Contact not found" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Failed to delete contact" } } } } } } }, "/api/contactLists.updateStatus": { "post": { "summary": "Update contact list subscription status", "description": "Updates the subscription status of a contact in a specific list. Can set status to active, pending, unsubscribed, bounced, or complained.\n\n**Note:** This endpoint only modifies **existing** list memberships. It does not add a contact to a list. To add a contact to a list, use the `/subscribe` endpoint (for public lists) or the `/api/contacts.import` endpoint (for any list, requires authentication).\n", "operationId": "updateContactListStatus", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateContactListStatusRequest" } } } }, "responses": { "200": { "description": "Status updated successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateContactListStatusResponse" } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "workspace_id is required" } }, "missingEmail": { "value": { "error": "email is required" } }, "missingListId": { "value": { "error": "list_id is required" } }, "invalidStatus": { "value": { "error": "invalid status value" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Contact list relationship not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "contact list not found" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/broadcasts.list": { "get": { "summary": "List broadcasts", "description": "Retrieves a list of broadcasts with pagination and optional filtering by status. Supports fetching template details for each variation.", "operationId": "listBroadcasts", "security": [ { "BearerAuth": [] } ], "parameters": [ { "name": "workspace_id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The ID of the workspace", "example": "ws_1234567890" }, { "name": "status", "in": "query", "required": false, "schema": { "type": "string", "enum": [ "draft", "scheduled", "sending", "paused", "sent", "cancelled", "failed", "testing", "test_completed", "winner_selected" ] }, "description": "Filter broadcasts by status" }, { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "default": 50 }, "description": "Maximum number of broadcasts to return", "example": 50 }, { "name": "offset", "in": "query", "required": false, "schema": { "type": "integer", "default": 0 }, "description": "Number of broadcasts to skip for pagination", "example": 0 }, { "name": "with_templates", "in": "query", "required": false, "schema": { "type": "boolean", "default": false }, "description": "Include full template details for each variation", "example": false } ], "responses": { "200": { "description": "List of broadcasts retrieved successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BroadcastListResponse" } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "workspace_id is required" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Failed to list broadcasts" } } } } } } }, "/api/broadcasts.get": { "get": { "summary": "Get a broadcast", "description": "Retrieves a single broadcast by ID. Optionally includes template details for each variation.", "operationId": "getBroadcast", "security": [ { "BearerAuth": [] } ], "parameters": [ { "name": "workspace_id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The ID of the workspace", "example": "ws_1234567890" }, { "name": "id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The ID of the broadcast", "example": "broadcast_12345" }, { "name": "with_templates", "in": "query", "required": false, "schema": { "type": "boolean", "default": false }, "description": "Include full template details for each variation", "example": false } ], "responses": { "200": { "description": "Broadcast retrieved successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "broadcast": { "$ref": "#/components/schemas/Broadcast" } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Broadcast not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Broadcast not found" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/broadcasts.create": { "post": { "summary": "Create a broadcast", "description": "Creates a new broadcast campaign in draft status.\n\n**Important:** Creating a broadcast does not schedule or send it. After creating the broadcast,\nyou must call the `/api/broadcasts.schedule` endpoint to schedule or send it immediately.\n", "operationId": "createBroadcast", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateBroadcastRequest" } } } }, "responses": { "201": { "description": "Broadcast created successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "broadcast": { "$ref": "#/components/schemas/Broadcast" } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingName": { "value": { "error": "name is required" } }, "missingList": { "value": { "error": "list is required" } }, "invalidTestSettings": { "value": { "error": "at least 2 variations are required for A/B testing" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Failed to create broadcast" } } } } } } }, "/api/broadcasts.update": { "post": { "summary": "Update a broadcast", "description": "Updates an existing broadcast. Only broadcasts in draft, scheduled, or paused status can be updated.", "operationId": "updateBroadcast", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateBroadcastRequest" } } } }, "responses": { "200": { "description": "Broadcast updated successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "broadcast": { "$ref": "#/components/schemas/Broadcast" } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "invalidStatus": { "value": { "error": "cannot update broadcast with status: sending" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Broadcast not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Broadcast not found" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/broadcasts.schedule": { "post": { "summary": "Schedule a broadcast", "description": "Schedules a broadcast for sending either immediately or at a specified time. This endpoint is restricted in demo mode.", "operationId": "scheduleBroadcast", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScheduleBroadcastRequest" } } } }, "responses": { "200": { "description": "Broadcast scheduled successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "example": true } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingDateTime": { "value": { "error": "scheduled_date and scheduled_time are required when not sending immediately" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Broadcast not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/broadcasts.pause": { "post": { "summary": "Pause a broadcast", "description": "Pauses a broadcast that is currently sending.", "operationId": "pauseBroadcast", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PauseBroadcastRequest" } } } }, "responses": { "200": { "description": "Broadcast paused successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "example": true } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Broadcast not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/broadcasts.resume": { "post": { "summary": "Resume a broadcast", "description": "Resumes a paused broadcast.", "operationId": "resumeBroadcast", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResumeBroadcastRequest" } } } }, "responses": { "200": { "description": "Broadcast resumed successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "example": true } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Broadcast not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/broadcasts.cancel": { "post": { "summary": "Cancel a broadcast", "description": "Cancels a scheduled broadcast.", "operationId": "cancelBroadcast", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CancelBroadcastRequest" } } } }, "responses": { "200": { "description": "Broadcast cancelled successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "example": true } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Broadcast not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/broadcasts.sendToIndividual": { "post": { "summary": "Send broadcast to individual", "description": "Sends a broadcast to a single recipient for testing purposes. Optionally specify which template variation to send.", "operationId": "sendBroadcastToIndividual", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendToIndividualRequest" } } } }, "responses": { "200": { "description": "Broadcast sent to individual successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "example": true } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Broadcast not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/broadcasts.delete": { "post": { "summary": "Delete a broadcast", "description": "Deletes a broadcast. This action is permanent and cannot be undone.", "operationId": "deleteBroadcast", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteBroadcastRequest" } } } }, "responses": { "200": { "description": "Broadcast deleted successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "example": true } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Broadcast not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/broadcasts.getTestResults": { "get": { "summary": "Get A/B test results", "description": "Retrieves the performance metrics for all variations in an A/B test broadcast.", "operationId": "getBroadcastTestResults", "security": [ { "BearerAuth": [] } ], "parameters": [ { "name": "workspace_id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The ID of the workspace", "example": "ws_1234567890" }, { "name": "id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The ID of the broadcast", "example": "broadcast_12345" } ], "responses": { "200": { "description": "Test results retrieved successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TestResultsResponse" } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Failed to get test results" } } } } } } }, "/api/broadcasts.selectWinner": { "post": { "summary": "Select winning A/B test variation", "description": "Manually selects the winning variation for an A/B test broadcast. The winning variation will be sent to the remaining audience. This endpoint is restricted in demo mode.", "operationId": "selectBroadcastWinner", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SelectWinnerRequest" } } } }, "responses": { "200": { "description": "Winner selected successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "example": true } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Failed to select winner" } } } } } } }, "/api/broadcasts.refreshGlobalFeed": { "post": { "summary": "Refresh global feed data", "description": "Fetches fresh data from the configured global feed URL and stores it in the broadcast.\nThe global feed must be enabled for the broadcast before calling this endpoint.\n", "operationId": "refreshGlobalFeed", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RefreshGlobalFeedRequest" } } } }, "responses": { "200": { "description": "Global feed data refreshed successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RefreshGlobalFeedResponse" } } } }, "400": { "description": "Bad request - global feed not enabled or validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "notEnabled": { "value": { "error": "global feed is not enabled for this broadcast" } }, "validation": { "value": { "error": "workspace_id is required" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Broadcast not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Broadcast not found" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Failed to refresh global feed" } } } } } } }, "/api/broadcasts.testRecipientFeed": { "post": { "summary": "Test recipient feed configuration", "description": "Tests the per-recipient feed configuration by fetching data for a specific contact or a random contact from the broadcast audience.\nThe recipient feed must be enabled for the broadcast before calling this endpoint.\n", "operationId": "testRecipientFeed", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TestRecipientFeedRequest" } } } }, "responses": { "200": { "description": "Recipient feed test completed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TestRecipientFeedResponse" } } } }, "400": { "description": "Bad request - recipient feed not enabled or validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "notEnabled": { "value": { "error": "recipient feed is not enabled for this broadcast" } }, "validation": { "value": { "error": "workspace_id is required" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Broadcast or contact not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "broadcastNotFound": { "value": { "error": "Broadcast not found" } }, "contactNotFound": { "value": { "error": "Contact not found" } } } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Failed to test recipient feed" } } } } } } }, "/api/templates.list": { "get": { "summary": "List templates", "description": "Retrieves a list of all templates in the workspace. Supports optional filtering by category and channel.", "operationId": "listTemplates", "security": [ { "BearerAuth": [] } ], "parameters": [ { "name": "workspace_id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The ID of the workspace", "example": "ws_1234567890" }, { "name": "category", "in": "query", "required": false, "schema": { "type": "string", "enum": [ "marketing", "transactional", "welcome", "opt_in", "unsubscribe", "bounce", "blocklist", "blog", "other" ] }, "description": "Filter templates by category" }, { "name": "channel", "in": "query", "required": false, "schema": { "type": "string", "enum": [ "email", "web" ] }, "description": "Filter templates by channel" } ], "responses": { "200": { "description": "List of templates retrieved successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "templates": { "type": "array", "items": { "$ref": "#/components/schemas/Template" } } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "workspace_id is required" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Failed to get templates" } } } } } } }, "/api/templates.get": { "get": { "summary": "Get a template", "description": "Retrieves a single template by ID. Optionally specify a version number to retrieve a specific version.", "operationId": "getTemplate", "security": [ { "BearerAuth": [] } ], "parameters": [ { "name": "workspace_id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The ID of the workspace", "example": "ws_1234567890" }, { "name": "id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The ID of the template", "example": "welcome_email" }, { "name": "version", "in": "query", "required": false, "schema": { "type": "integer", "format": "int64" }, "description": "Specific version number (defaults to latest)", "example": 1 } ], "responses": { "200": { "description": "Template retrieved successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "template": { "$ref": "#/components/schemas/Template" } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Template not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Template not found" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/templates.create": { "post": { "summary": "Create a template", "description": "Creates a new template. Each template must have a channel (email or web) with corresponding channel-specific content.", "operationId": "createTemplate", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateTemplateRequest" } } } }, "responses": { "201": { "description": "Template created successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "template": { "$ref": "#/components/schemas/Template" } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "duplicateId": { "value": { "error": "Template id already exists" } }, "missingEmail": { "value": { "error": "email is required for channel 'email'" } }, "invalidId": { "value": { "error": "id must contain only letters, numbers, underscores, and hyphens" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Failed to create template" } } } } } } }, "/api/templates.update": { "post": { "summary": "Update a template", "description": "Updates an existing template. Creates a new version of the template.", "operationId": "updateTemplate", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateTemplateRequest" } } } }, "responses": { "200": { "description": "Template updated successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "template": { "$ref": "#/components/schemas/Template" } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Template not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Template not found" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Failed to update template" } } } } } } }, "/api/templates.delete": { "post": { "summary": "Delete a template", "description": "Soft-deletes a template. The template will be marked as deleted but not removed from the database.", "operationId": "deleteTemplate", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteTemplateRequest" } } } }, "responses": { "200": { "description": "Template deleted successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "example": true } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Template not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Template not found" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Failed to delete template" } } } } } } }, "/api/templates.compile": { "post": { "summary": "Compile template", "description": "Compiles an MJML template with provided data, returning the rendered HTML.\nWhen `subject` and/or `subject_preview` are provided, they are rendered\nthrough the same Liquid engine used at send time and returned alongside\nthe HTML so callers do not need to run a separate Liquid pass to preview\nthe subject line. Useful for previewing templates before saving.\n", "operationId": "compileTemplate", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CompileTemplateRequest" } } } }, "responses": { "200": { "description": "Template compiled successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CompileTemplateResponse" } } } }, "400": { "description": "Bad request - compilation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Compilation failed: Invalid MJML syntax" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/customEvents.import": { "post": { "summary": "Import custom events", "description": "Imports multiple custom events in a single batch operation. Maximum 50 events per request. Auto-creates contacts if they don't exist.", "operationId": "importCustomEvents", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImportCustomEventsRequest" } } } }, "responses": { "201": { "description": "Custom events imported successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImportCustomEventsResponse" } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "workspace_id is required" } }, "emptyEvents": { "value": { "error": "events array cannot be empty" } }, "tooManyEvents": { "value": { "error": "maximum 50 events allowed per batch" } }, "invalidEventName": { "value": { "error": "invalid event name: must contain only lowercase letters, numbers, underscores, dots, and slashes" } }, "missingRequiredFields": { "value": { "error": "event_name, external_id, and email are required for each event" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "403": { "description": "Forbidden - missing required permission", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "contacts:write permission required" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Failed to create custom events" } } } } } } }, "/api/webhookSubscriptions.create": { "post": { "summary": "Create a webhook subscription", "description": "Creates a new webhook subscription to receive HTTP callbacks when specified events occur in the workspace.", "operationId": "createWebhookSubscription", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateWebhookSubscriptionRequest" } } } }, "responses": { "201": { "description": "Webhook subscription created successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateWebhookSubscriptionResponse" } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "workspace_id is required" } }, "invalidUrl": { "value": { "error": "url must be a valid HTTPS URL" } }, "emptyEventTypes": { "value": { "error": "at least one event type is required" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/webhookSubscriptions.list": { "get": { "summary": "List webhook subscriptions", "description": "Returns all webhook subscriptions for the specified workspace.", "operationId": "listWebhookSubscriptions", "security": [ { "BearerAuth": [] } ], "parameters": [ { "name": "workspace_id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The ID of the workspace", "example": "ws_1234567890" } ], "responses": { "200": { "description": "List of webhook subscriptions", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListWebhookSubscriptionsResponse" } } } }, "400": { "description": "Bad request - missing workspace_id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "workspace_id is required" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/webhookSubscriptions.get": { "get": { "summary": "Get a webhook subscription", "description": "Retrieves a specific webhook subscription by ID.", "operationId": "getWebhookSubscription", "security": [ { "BearerAuth": [] } ], "parameters": [ { "name": "workspace_id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The ID of the workspace", "example": "ws_1234567890" }, { "name": "id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The ID of the webhook subscription", "example": "whsub_a1b2c3d4e5f6" } ], "responses": { "200": { "description": "Webhook subscription found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GetWebhookSubscriptionResponse" } } } }, "400": { "description": "Bad request - missing parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "workspace_id is required" } }, "missingId": { "value": { "error": "id is required" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Webhook subscription not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Webhook subscription not found" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/webhookSubscriptions.update": { "post": { "summary": "Update a webhook subscription", "description": "Updates an existing webhook subscription with new configuration.", "operationId": "updateWebhookSubscription", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateWebhookSubscriptionRequest" } } } }, "responses": { "200": { "description": "Webhook subscription updated successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateWebhookSubscriptionResponse" } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "workspace_id is required" } }, "missingId": { "value": { "error": "id is required" } }, "invalidUrl": { "value": { "error": "url must be a valid HTTPS URL" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Webhook subscription not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/webhookSubscriptions.delete": { "post": { "summary": "Delete a webhook subscription", "description": "Permanently deletes a webhook subscription. This action cannot be undone.", "operationId": "deleteWebhookSubscription", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteWebhookSubscriptionRequest" } } } }, "responses": { "200": { "description": "Webhook subscription deleted successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "example": true } } } } } }, "400": { "description": "Bad request - missing parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "workspace_id is required" } }, "missingId": { "value": { "error": "id is required" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/webhookSubscriptions.toggle": { "post": { "summary": "Toggle webhook subscription enabled state", "description": "Enables or disables a webhook subscription. Disabled subscriptions will not receive events.", "operationId": "toggleWebhookSubscription", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ToggleWebhookSubscriptionRequest" } } } }, "responses": { "200": { "description": "Webhook subscription toggled successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ToggleWebhookSubscriptionResponse" } } } }, "400": { "description": "Bad request - missing parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "workspace_id is required" } }, "missingId": { "value": { "error": "id is required" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/webhookSubscriptions.regenerateSecret": { "post": { "summary": "Regenerate webhook secret", "description": "Generates a new signing secret for the webhook subscription. The old secret will immediately become invalid.", "operationId": "regenerateWebhookSecret", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RegenerateWebhookSecretRequest" } } } }, "responses": { "200": { "description": "Webhook secret regenerated successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RegenerateWebhookSecretResponse" } } } }, "400": { "description": "Bad request - missing parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "workspace_id is required" } }, "missingId": { "value": { "error": "id is required" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/webhookSubscriptions.deliveries": { "get": { "summary": "Get webhook delivery history", "description": "Returns the delivery history for a webhook subscription, including status and response information.", "operationId": "getWebhookDeliveries", "security": [ { "BearerAuth": [] } ], "parameters": [ { "name": "workspace_id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "The ID of the workspace", "example": "ws_1234567890" }, { "name": "subscription_id", "in": "query", "required": false, "schema": { "type": "string" }, "description": "The ID of the webhook subscription (optional - if not provided, returns all deliveries for the workspace)", "example": "whsub_a1b2c3d4e5f6" }, { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }, "description": "Number of deliveries to return (1-100)", "example": 20 }, { "name": "offset", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 0, "default": 0 }, "description": "Offset for pagination", "example": 0 } ], "responses": { "200": { "description": "List of webhook deliveries", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListWebhookDeliveriesResponse" } } } }, "400": { "description": "Bad request - missing parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "workspace_id is required" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/webhookSubscriptions.test": { "post": { "summary": "Send a test webhook", "description": "Sends a test webhook to the subscription's URL to verify connectivity and configuration.", "operationId": "testWebhookSubscription", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TestWebhookRequest" } } } }, "responses": { "200": { "description": "Test webhook sent (check response for success/failure)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TestWebhookResponse" } } } }, "400": { "description": "Bad request - missing parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "workspace_id is required" } }, "missingId": { "value": { "error": "id is required" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Webhook subscription not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Webhook subscription not found" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/api/webhookSubscriptions.eventTypes": { "get": { "summary": "List available event types", "description": "Returns a list of all available webhook event types that can be subscribed to.", "operationId": "listWebhookEventTypes", "security": [ { "BearerAuth": [] } ], "responses": { "200": { "description": "List of available event types", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListWebhookEventTypesResponse" } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/subscribe": { "post": { "summary": "Subscribe to email lists", "description": "Subscribe a contact to one or more email lists. This is a public endpoint that doesn't require authentication.\n\n**Important:** For unauthenticated requests, only **public lists** can be subscribed to. To subscribe to private lists, you can either:\n- Provide a valid `email_hmac` in the contact object (used by the notification center for re-subscribing after unsubscribing)\n- Use the authenticated `/api/lists.subscribe` endpoint with a bearer token\n\nIf the list has double opt-in enabled, a confirmation email will be sent.\n", "operationId": "subscribeToLists", "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SubscribeToListsRequest" } } } }, "responses": { "200": { "description": "Subscription successful", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the subscription was successful", "example": true } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "workspace_id is required" } }, "invalidEmail": { "value": { "error": "invalid contact: invalid email format" } }, "missingListIds": { "value": { "error": "list_ids is required" } }, "listNotPublic": { "value": { "error": "list is not public" } } } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Failed to subscribe to lists" } } } } } } }, "/api/lists.subscribe": { "post": { "summary": "Subscribe to email lists (authenticated)", "description": "Subscribe a contact to one or more email lists. This is an authenticated endpoint that requires a bearer token.\n\nUnlike the public `/subscribe` endpoint, this endpoint can subscribe contacts to **any list** (public or private) as long as the authenticated user has write permission on lists.\n\n**Note:** Double opt-in is bypassed for authenticated requests. Contacts are immediately set to `active` status regardless of the list's double opt-in setting. This allows administrators to manually add contacts without requiring email confirmation.\n", "operationId": "subscribeToListsAuthenticated", "security": [ { "BearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SubscribeToListsRequest" } } } }, "responses": { "200": { "description": "Subscription successful", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the subscription was successful", "example": true } } } } } }, "400": { "description": "Bad request - validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingWorkspaceId": { "value": { "error": "workspace_id is required" } }, "invalidEmail": { "value": { "error": "invalid contact: invalid email format" } }, "missingListIds": { "value": { "error": "list_ids is required" } } } } } }, "401": { "description": "Unauthorized - invalid or missing authentication token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Failed to subscribe to lists" } } } } } } }, "/api/user.rootSignin": { "post": { "summary": "Root user programmatic signin", "security": [], "description": "Authenticates the root user using HMAC signature for programmatic access.\nThis endpoint is designed for automation scenarios like Infrastructure-as-Code\ndeployments, CI/CD pipelines, and automated testing where magic link\nauthentication is impractical.\n\n**Security Features:**\n- HMAC-SHA256 signature verification using the application's secret key\n- 60-second timestamp window to prevent replay attacks\n- Rate limited to 5 attempts per 5 minutes per email\n- Only works for a configured root email address (ROOT_EMAIL may list several, comma/semicolon-separated)\n\n**How to generate the signature:**\n```bash\nSECRET_KEY=\"your-notifuse-secret-key\"\nROOT_EMAIL=\"admin@example.com\"\nTIMESTAMP=$(date +%s)\nMESSAGE=\"${ROOT_EMAIL}:${TIMESTAMP}\"\nSIGNATURE=$(echo -n \"$MESSAGE\" | openssl dgst -sha256 -hmac \"$SECRET_KEY\" | awk '{print $2}')\n```\n", "operationId": "rootSignin", "tags": [ "Authentication" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RootSigninRequest" }, "example": { "email": "admin@example.com", "timestamp": 1735600000, "signature": "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456" } } } }, "responses": { "200": { "description": "Authentication successful", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RootSigninResponse" }, "example": { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidXNyXzEyMzQ1Njc4OTAiLCJzZXNzaW9uX2lkIjoic2VzXzEyMzQ1Njc4OTAiLCJleHAiOjE3MzU2ODY0MDB9.signature", "user": { "id": "usr_1234567890", "email": "admin@example.com", "name": "Admin User", "created_at": "2025-01-01T00:00:00Z", "updated_at": "2025-01-01T00:00:00Z" }, "expires_at": "2025-01-01T12:00:00Z" } } } }, "400": { "description": "Bad request - missing required fields", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "missingFields": { "summary": "Missing required fields", "value": { "error": "Missing required fields: email, timestamp, signature" } }, "invalidBody": { "summary": "Invalid JSON body", "value": { "error": "Invalid request body" } } } } } }, "401": { "description": "Unauthorized - invalid credentials", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { "invalidCredentials": { "summary": "Invalid email, timestamp, or signature", "value": { "error": "Invalid credentials" } }, "rateLimited": { "summary": "Too many failed attempts", "value": { "error": "Invalid credentials" } } } } } }, "405": { "description": "Method not allowed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "example": { "error": "Method not allowed" } } } } } } } }, "components": { "securitySchemes": { "BearerAuth": { "type": "http", "scheme": "bearer", "description": "API token for authentication" } }, "schemas": { "ErrorResponse": { "type": "object", "properties": { "error": { "type": "string", "description": "Error message" } }, "required": [ "error" ] }, "SendTransactionalRequest": { "type": "object", "required": [ "workspace_id", "notification" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "notification": { "$ref": "#/components/schemas/TransactionalNotificationSendParams" } } }, "TransactionalNotificationSendParams": { "type": "object", "required": [ "id", "contact", "channels" ], "properties": { "id": { "type": "string", "description": "ID of the notification to send", "example": "welcome_email" }, "external_id": { "type": "string", "nullable": true, "description": "External ID for idempotency checks", "example": "txn_12345" }, "contact": { "$ref": "#/components/schemas/Contact" }, "channels": { "type": "array", "description": "Channels to send through (at least one required)", "minItems": 1, "items": { "type": "string", "enum": [ "email" ] }, "example": [ "email" ] }, "data": { "type": "object", "additionalProperties": true, "description": "Data to populate the template with", "example": { "user_name": "John Doe", "activation_link": "https://example.com/activate/abc123" } }, "metadata": { "type": "object", "additionalProperties": true, "description": "Additional metadata for tracking", "example": { "campaign_id": "spring_promo_2023", "source": "user_signup" } }, "email_options": { "type": "object", "description": "Email-specific options", "properties": { "from_name": { "type": "string", "nullable": true, "description": "Override default sender from name", "example": "Support Team" }, "subject": { "type": "string", "nullable": true, "description": "Override template subject line. Supports Liquid templating variables.", "maxLength": 255, "example": "Welcome, {{ name }}!" }, "subject_preview": { "type": "string", "nullable": true, "description": "Override template preheader/preview text. Supports Liquid templating variables.", "maxLength": 255, "example": "Your order has been confirmed" }, "cc": { "type": "array", "description": "CC email addresses", "items": { "type": "string", "format": "email" }, "example": [ "manager@example.com" ] }, "bcc": { "type": "array", "description": "BCC email addresses", "items": { "type": "string", "format": "email" }, "example": [ "archive@example.com" ] }, "reply_to": { "type": "string", "format": "email", "description": "Reply-To email address", "example": "support@example.com" }, "attachments": { "type": "array", "description": "Email attachments (max 20 files, 3MB per file, 10MB total)", "items": { "$ref": "#/components/schemas/EmailAttachment" }, "maxItems": 20, "example": [ { "filename": "invoice.pdf", "content": "JVBERi0xLjQKJeLjz9MKMy4uLg==", "content_type": "application/pdf", "disposition": "attachment" } ] } } } } }, "Contact": { "type": "object", "required": [ "email" ], "properties": { "email": { "type": "string", "format": "email", "description": "Email address of the contact. This is the contact's unique identifier.", "example": "user@example.com" }, "external_id": { "type": "string", "nullable": true, "description": "Identifier for the contact in your own system. Not unique — several contacts may share the same external_id.", "example": "user_12345" }, "timezone": { "type": "string", "nullable": true, "description": "Timezone of the contact", "example": "America/New_York" }, "language": { "type": "string", "nullable": true, "description": "Preferred language of the contact", "example": "en-US" }, "first_name": { "type": "string", "nullable": true, "description": "First name of the contact", "example": "John" }, "last_name": { "type": "string", "nullable": true, "description": "Last name of the contact", "example": "Doe" }, "full_name": { "type": "string", "nullable": true, "description": "Full name of the contact (for systems that don't have separate first/last names)", "example": "John Doe" }, "phone": { "type": "string", "nullable": true, "description": "Phone number of the contact", "example": "+15551234567" }, "address_line_1": { "type": "string", "nullable": true, "description": "First line of address", "example": "123 Main St" }, "address_line_2": { "type": "string", "nullable": true, "description": "Second line of address", "example": "Apt 4B" }, "country": { "type": "string", "nullable": true, "description": "Country of the contact", "example": "US" }, "postcode": { "type": "string", "nullable": true, "description": "Postal code", "example": "10001" }, "state": { "type": "string", "nullable": true, "description": "State or province", "example": "NY" }, "job_title": { "type": "string", "nullable": true, "description": "Job title of the contact", "example": "Software Engineer" }, "custom_string_1": { "type": "string", "nullable": true, "description": "Custom string field 1", "example": "Premium tier" }, "custom_string_2": { "type": "string", "nullable": true, "description": "Custom string field 2" }, "custom_string_3": { "type": "string", "nullable": true, "description": "Custom string field 3" }, "custom_string_4": { "type": "string", "nullable": true, "description": "Custom string field 4" }, "custom_string_5": { "type": "string", "nullable": true, "description": "Custom string field 5" }, "custom_number_1": { "type": "number", "format": "float", "nullable": true, "description": "Custom number field 1", "example": 42 }, "custom_number_2": { "type": "number", "format": "float", "nullable": true, "description": "Custom number field 2" }, "custom_number_3": { "type": "number", "format": "float", "nullable": true, "description": "Custom number field 3" }, "custom_number_4": { "type": "number", "format": "float", "nullable": true, "description": "Custom number field 4" }, "custom_number_5": { "type": "number", "format": "float", "nullable": true, "description": "Custom number field 5" }, "custom_datetime_1": { "type": "string", "format": "date-time", "nullable": true, "description": "Custom datetime field 1", "example": "2023-06-01T09:00:00Z" }, "custom_datetime_2": { "type": "string", "format": "date-time", "nullable": true, "description": "Custom datetime field 2" }, "custom_datetime_3": { "type": "string", "format": "date-time", "nullable": true, "description": "Custom datetime field 3" }, "custom_datetime_4": { "type": "string", "format": "date-time", "nullable": true, "description": "Custom datetime field 4" }, "custom_datetime_5": { "type": "string", "format": "date-time", "nullable": true, "description": "Custom datetime field 5" }, "custom_json_1": { "type": "object", "nullable": true, "description": "Custom JSON field 1", "example": { "preferences": { "theme": "dark", "notifications": true } } }, "custom_json_2": { "type": "object", "nullable": true, "description": "Custom JSON field 2" }, "custom_json_3": { "type": "object", "nullable": true, "description": "Custom JSON field 3" }, "custom_json_4": { "type": "object", "nullable": true, "description": "Custom JSON field 4" }, "custom_json_5": { "type": "object", "nullable": true, "description": "Custom JSON field 5" }, "created_at": { "type": "string", "format": "date-time", "readOnly": true, "description": "When the contact was created (read-only, set by server)", "example": "2023-01-15T10:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "readOnly": true, "description": "When the contact was last updated (read-only, set by server)", "example": "2023-04-22T15:45:00Z" }, "contact_lists": { "type": "array", "readOnly": true, "description": "Lists the contact is subscribed to (read-only, included in GET responses only)", "items": { "$ref": "#/components/schemas/ContactList" }, "example": [ { "email": "user@example.com", "list_id": "newsletter", "list_name": "Newsletter", "status": "active", "created_at": "2023-01-15T10:30:00Z", "updated_at": "2023-01-15T10:30:00Z", "deleted_at": null } ] }, "contact_segments": { "type": "array", "readOnly": true, "description": "Segments the contact belongs to (read-only, included in GET responses only)", "items": { "$ref": "#/components/schemas/ContactSegment" } } } }, "ContactInput": { "type": "object", "required": [ "email" ], "properties": { "email": { "type": "string", "format": "email", "description": "Email address of the contact. This is the contact's unique identifier — upserts always match contacts by email address.", "example": "user@example.com" }, "external_id": { "type": "string", "nullable": true, "description": "Optional identifier for the contact in your own system (e.g. your user ID). Stored and searchable, but not unique and never used to match contacts during upserts — sending an existing external_id with a new email address creates a second contact.", "example": "user_12345" }, "timezone": { "type": "string", "nullable": true, "description": "Timezone of the contact", "example": "America/New_York" }, "language": { "type": "string", "nullable": true, "description": "Preferred language of the contact", "example": "en-US" }, "first_name": { "type": "string", "nullable": true, "description": "First name of the contact", "example": "John" }, "last_name": { "type": "string", "nullable": true, "description": "Last name of the contact", "example": "Doe" }, "full_name": { "type": "string", "nullable": true, "description": "Full name of the contact (for systems that don't have separate first/last names)", "example": "John Doe" }, "phone": { "type": "string", "nullable": true, "description": "Phone number of the contact", "example": "+15551234567" }, "address_line_1": { "type": "string", "nullable": true, "description": "First line of address", "example": "123 Main St" }, "address_line_2": { "type": "string", "nullable": true, "description": "Second line of address", "example": "Apt 4B" }, "country": { "type": "string", "nullable": true, "description": "Country of the contact", "example": "US" }, "postcode": { "type": "string", "nullable": true, "description": "Postal code", "example": "10001" }, "state": { "type": "string", "nullable": true, "description": "State or province", "example": "NY" }, "job_title": { "type": "string", "nullable": true, "description": "Job title of the contact", "example": "Software Engineer" }, "custom_string_1": { "type": "string", "nullable": true, "description": "Custom string field 1", "example": "Premium tier" }, "custom_string_2": { "type": "string", "nullable": true, "description": "Custom string field 2" }, "custom_string_3": { "type": "string", "nullable": true, "description": "Custom string field 3" }, "custom_string_4": { "type": "string", "nullable": true, "description": "Custom string field 4" }, "custom_string_5": { "type": "string", "nullable": true, "description": "Custom string field 5" }, "custom_number_1": { "type": "number", "format": "float", "nullable": true, "description": "Custom number field 1", "example": 42 }, "custom_number_2": { "type": "number", "format": "float", "nullable": true, "description": "Custom number field 2" }, "custom_number_3": { "type": "number", "format": "float", "nullable": true, "description": "Custom number field 3" }, "custom_number_4": { "type": "number", "format": "float", "nullable": true, "description": "Custom number field 4" }, "custom_number_5": { "type": "number", "format": "float", "nullable": true, "description": "Custom number field 5" }, "custom_datetime_1": { "type": "string", "format": "date-time", "nullable": true, "description": "Custom datetime field 1", "example": "2023-06-01T09:00:00Z" }, "custom_datetime_2": { "type": "string", "format": "date-time", "nullable": true, "description": "Custom datetime field 2" }, "custom_datetime_3": { "type": "string", "format": "date-time", "nullable": true, "description": "Custom datetime field 3" }, "custom_datetime_4": { "type": "string", "format": "date-time", "nullable": true, "description": "Custom datetime field 4" }, "custom_datetime_5": { "type": "string", "format": "date-time", "nullable": true, "description": "Custom datetime field 5" }, "custom_json_1": { "type": "object", "nullable": true, "description": "Custom JSON field 1 (must be a JSON object or array)", "example": { "preferences": { "theme": "dark", "notifications": true } } }, "custom_json_2": { "type": "object", "nullable": true, "description": "Custom JSON field 2 (must be a JSON object or array)" }, "custom_json_3": { "type": "object", "nullable": true, "description": "Custom JSON field 3 (must be a JSON object or array)" }, "custom_json_4": { "type": "object", "nullable": true, "description": "Custom JSON field 4 (must be a JSON object or array)" }, "custom_json_5": { "type": "object", "nullable": true, "description": "Custom JSON field 5 (must be a JSON object or array)" } } }, "ContactList": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "Email address of the contact", "example": "user@example.com" }, "list_id": { "type": "string", "description": "ID of the list", "example": "newsletter" }, "list_name": { "type": "string", "description": "Name of the list", "example": "Newsletter" }, "status": { "type": "string", "enum": [ "active", "pending", "unsubscribed", "bounced", "complained" ], "description": "Subscription status", "example": "active" }, "created_at": { "type": "string", "format": "date-time", "description": "When the contact was subscribed to this list", "example": "2023-01-15T10:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "When the subscription was last updated", "example": "2023-01-15T10:30:00Z" }, "deleted_at": { "type": "string", "format": "date-time", "nullable": true, "description": "When the subscription was deleted (null if active)", "example": null } } }, "ContactSegment": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "Email address of the contact", "example": "user@example.com" }, "segment_id": { "type": "string", "description": "ID of the segment", "example": "premium_users" }, "version": { "type": "integer", "format": "int64", "description": "Version of the segment computation", "example": 1 }, "matched_at": { "type": "string", "format": "date-time", "description": "When the contact was matched to this segment", "example": "2023-01-15T10:30:00Z" }, "computed_at": { "type": "string", "format": "date-time", "description": "When the segment was last computed", "example": "2023-01-15T10:30:00Z" } } }, "SubscribeToListsRequest": { "type": "object", "required": [ "workspace_id", "contact", "list_ids" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "contact": { "$ref": "#/components/schemas/SubscriptionContact" }, "list_ids": { "type": "array", "description": "Array of list IDs to subscribe the contact to", "items": { "type": "string" }, "example": [ "newsletter", "product_updates" ], "minItems": 1 } } }, "SubscriptionContact": { "type": "object", "required": [ "email" ], "properties": { "email": { "type": "string", "format": "email", "description": "Email address of the contact", "example": "user@example.com" }, "email_hmac": { "type": "string", "description": "HMAC of the email for authenticated subscription (optional)", "example": "a1b2c3d4e5f6..." }, "external_id": { "type": "string", "nullable": true, "description": "Optional identifier for the contact in your own system. Not unique — contacts are identified by email address.", "example": "user_12345" }, "timezone": { "type": "string", "nullable": true, "description": "Timezone of the contact", "example": "America/New_York" }, "language": { "type": "string", "nullable": true, "description": "Preferred language of the contact", "example": "en-US" }, "first_name": { "type": "string", "nullable": true, "description": "First name of the contact", "example": "John" }, "last_name": { "type": "string", "nullable": true, "description": "Last name of the contact", "example": "Doe" }, "full_name": { "type": "string", "nullable": true, "description": "Full name of the contact (for systems that don't have separate first/last names)", "example": "John Doe" }, "phone": { "type": "string", "nullable": true, "description": "Phone number of the contact", "example": "+15551234567" }, "address_line_1": { "type": "string", "nullable": true, "description": "First line of address", "example": "123 Main St" }, "address_line_2": { "type": "string", "nullable": true, "description": "Second line of address", "example": "Apt 4B" }, "country": { "type": "string", "nullable": true, "description": "Country of the contact", "example": "US" }, "postcode": { "type": "string", "nullable": true, "description": "Postal code", "example": "10001" }, "state": { "type": "string", "nullable": true, "description": "State or province", "example": "NY" }, "job_title": { "type": "string", "nullable": true, "description": "Job title of the contact", "example": "Software Engineer" }, "custom_string_1": { "type": "string", "nullable": true, "description": "Custom string field 1", "example": "Premium tier" }, "custom_string_2": { "type": "string", "nullable": true, "description": "Custom string field 2" }, "custom_string_3": { "type": "string", "nullable": true, "description": "Custom string field 3" }, "custom_string_4": { "type": "string", "nullable": true, "description": "Custom string field 4" }, "custom_string_5": { "type": "string", "nullable": true, "description": "Custom string field 5" }, "custom_number_1": { "type": "number", "format": "float", "nullable": true, "description": "Custom number field 1", "example": 42 }, "custom_number_2": { "type": "number", "format": "float", "nullable": true, "description": "Custom number field 2" }, "custom_number_3": { "type": "number", "format": "float", "nullable": true, "description": "Custom number field 3" }, "custom_number_4": { "type": "number", "format": "float", "nullable": true, "description": "Custom number field 4" }, "custom_number_5": { "type": "number", "format": "float", "nullable": true, "description": "Custom number field 5" }, "custom_datetime_1": { "type": "string", "format": "date-time", "nullable": true, "description": "Custom datetime field 1", "example": "2023-06-01T09:00:00Z" }, "custom_datetime_2": { "type": "string", "format": "date-time", "nullable": true, "description": "Custom datetime field 2" }, "custom_datetime_3": { "type": "string", "format": "date-time", "nullable": true, "description": "Custom datetime field 3" }, "custom_datetime_4": { "type": "string", "format": "date-time", "nullable": true, "description": "Custom datetime field 4" }, "custom_datetime_5": { "type": "string", "format": "date-time", "nullable": true, "description": "Custom datetime field 5" }, "custom_json_1": { "type": "object", "nullable": true, "description": "Custom JSON field 1", "example": { "preferences": { "theme": "dark", "notifications": true } } }, "custom_json_2": { "type": "object", "nullable": true, "description": "Custom JSON field 2" }, "custom_json_3": { "type": "object", "nullable": true, "description": "Custom JSON field 3" }, "custom_json_4": { "type": "object", "nullable": true, "description": "Custom JSON field 4" }, "custom_json_5": { "type": "object", "nullable": true, "description": "Custom JSON field 5" } } }, "UpsertContactRequest": { "type": "object", "required": [ "workspace_id", "contact" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "contact": { "$ref": "#/components/schemas/ContactInput" } } }, "UpsertContactResponse": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "Email address of the contact", "example": "user@example.com" }, "action": { "type": "string", "enum": [ "create", "update", "error" ], "description": "The action that was performed: 'create' for new contacts, 'update' for existing contacts, 'error' if validation failed", "example": "create" }, "error": { "type": "string", "nullable": true, "description": "Error message if the operation failed", "example": null } } }, "DeleteContactRequest": { "type": "object", "required": [ "workspace_id", "email" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "email": { "type": "string", "format": "email", "description": "Email address of the contact to delete", "example": "user@example.com" } } }, "BatchImportContactsRequest": { "type": "object", "required": [ "workspace_id", "contacts" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "contacts": { "type": "array", "description": "Array of contacts to import (create or update)", "items": { "$ref": "#/components/schemas/ContactInput" }, "minItems": 1, "example": [ { "email": "user1@example.com", "first_name": "John", "last_name": "Doe" }, { "email": "user2@example.com", "first_name": "Jane", "last_name": "Smith" } ] }, "subscribe_to_lists": { "type": "array", "description": "Optional array of list IDs to subscribe all contacts to", "items": { "type": "string" }, "example": [ "newsletter", "product_updates" ] } } }, "BatchImportContactsResponse": { "type": "object", "properties": { "operations": { "type": "array", "description": "Array of operation results, one for each contact in the request", "items": { "$ref": "#/components/schemas/UpsertContactOperation" } }, "error": { "type": "string", "nullable": true, "description": "Global error message if the entire operation failed", "example": null } } }, "UpsertContactOperation": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "Email address of the contact", "example": "user@example.com" }, "action": { "type": "string", "enum": [ "create", "update", "error" ], "description": "The action that was performed: 'create' for new contacts, 'update' for existing contacts, 'error' for failed operations", "example": "create" }, "error": { "type": "string", "nullable": true, "description": "Error message if this specific contact operation failed", "example": null } } }, "UpdateContactListStatusRequest": { "type": "object", "required": [ "workspace_id", "email", "list_id", "status" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "email": { "type": "string", "format": "email", "description": "Email address of the contact", "example": "user@example.com" }, "list_id": { "type": "string", "description": "ID of the list", "example": "newsletter" }, "status": { "type": "string", "enum": [ "active", "pending", "unsubscribed", "bounced", "complained" ], "description": "New subscription status", "example": "active" } } }, "UpdateContactListStatusResponse": { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the operation was successful", "example": true }, "message": { "type": "string", "description": "Status message", "example": "status updated successfully" }, "found": { "type": "boolean", "description": "Whether the contact was found in the list", "example": true } } }, "ListContactsResponse": { "type": "object", "properties": { "contacts": { "type": "array", "description": "Array of contacts matching the query", "items": { "$ref": "#/components/schemas/Contact" } }, "next_cursor": { "type": "string", "nullable": true, "description": "Cursor for fetching the next page of results. Null if no more results.", "example": "MjAyMy0wMS0xNVQxMDozMDowMFp+dXNlckBleGFtcGxlLmNvbQ==" } } }, "CountContactsResponse": { "type": "object", "properties": { "total_contacts": { "type": "integer", "description": "Total number of contacts in the workspace", "example": 1523 } } }, "EmailAttachment": { "type": "object", "required": [ "filename", "content" ], "properties": { "filename": { "type": "string", "description": "Name of the file (max 255 characters, no path separators)", "example": "invoice.pdf", "maxLength": 255 }, "content": { "type": "string", "format": "byte", "description": "Base64-encoded file content (max 3MB per file)", "example": "JVBERi0xLjQKJeLjz9MKMy4uLg==" }, "content_type": { "type": "string", "description": "MIME type of the file (auto-detected if not provided)", "example": "application/pdf" }, "disposition": { "type": "string", "enum": [ "attachment", "inline" ], "description": "How the attachment should be displayed (defaults to 'attachment')", "example": "attachment", "default": "attachment" }, "content_id": { "type": "string", "description": "Content-ID for inline attachments, referenced from the HTML body as . Only allowed when disposition is 'inline'. May only contain letters, digits, and the characters . _ - @ (max 255 characters). Defaults to the filename when omitted.", "example": "checkInQr", "maxLength": 255 } } }, "Broadcast": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier for the broadcast", "example": "broadcast_12345" }, "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "name": { "type": "string", "description": "Name of the broadcast", "example": "Spring Newsletter 2024", "maxLength": 255 }, "channel_type": { "type": "string", "description": "Communication channel type", "example": "email" }, "status": { "type": "string", "enum": [ "draft", "scheduled", "processing", "paused", "processed", "cancelled", "failed", "testing", "test_completed", "winner_selected" ], "description": "Current status of the broadcast", "example": "draft" }, "audience": { "$ref": "#/components/schemas/AudienceSettings" }, "schedule": { "$ref": "#/components/schemas/ScheduleSettings" }, "test_settings": { "$ref": "#/components/schemas/BroadcastTestSettings" }, "utm_parameters": { "$ref": "#/components/schemas/UTMParameters" }, "data_feed": { "$ref": "#/components/schemas/DataFeedSettings" }, "metadata": { "type": "object", "additionalProperties": true, "description": "Custom metadata for the broadcast" }, "winning_template": { "type": "string", "nullable": true, "description": "ID of the winning template variation", "example": "template_winner" }, "test_sent_at": { "type": "string", "format": "date-time", "nullable": true, "description": "When the A/B test was sent" }, "winner_sent_at": { "type": "string", "format": "date-time", "nullable": true, "description": "When the winning variation was sent" }, "enqueued_count": { "type": "integer", "description": "Number of emails added to the queue by orchestrator", "example": 1000 }, "test_phase_recipient_count": { "type": "integer", "description": "Number of recipients in test phase" }, "winner_phase_recipient_count": { "type": "integer", "description": "Number of recipients in winner phase" }, "created_at": { "type": "string", "format": "date-time", "description": "When the broadcast was created" }, "updated_at": { "type": "string", "format": "date-time", "description": "When the broadcast was last updated" }, "started_at": { "type": "string", "format": "date-time", "nullable": true, "description": "When the broadcast started sending" }, "completed_at": { "type": "string", "format": "date-time", "nullable": true, "description": "When the broadcast completed sending" }, "cancelled_at": { "type": "string", "format": "date-time", "nullable": true, "description": "When the broadcast was cancelled" }, "paused_at": { "type": "string", "format": "date-time", "nullable": true, "description": "When the broadcast was paused" }, "pause_reason": { "type": "string", "nullable": true, "description": "Reason for pausing the broadcast" } } }, "BroadcastTestSettings": { "type": "object", "properties": { "enabled": { "type": "boolean", "description": "Whether A/B testing is enabled", "example": true }, "sample_percentage": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Percentage of audience to use for testing", "example": 20 }, "auto_send_winner": { "type": "boolean", "description": "Automatically send winning variation to remaining audience", "example": true }, "auto_send_winner_metric": { "type": "string", "enum": [ "open_rate", "click_rate" ], "description": "Metric used to determine the winner", "example": "open_rate" }, "test_duration_hours": { "type": "integer", "minimum": 1, "maximum": 168, "description": "Duration of the test in hours (max 7 days)", "example": 24 }, "variations": { "type": "array", "description": "Test variations (2-8 variations allowed)", "minItems": 2, "maxItems": 8, "items": { "$ref": "#/components/schemas/BroadcastVariation" } } } }, "BroadcastVariation": { "type": "object", "required": [ "template_id" ], "properties": { "variation_name": { "type": "string", "description": "Name of this variation", "example": "Variation A" }, "template_id": { "type": "string", "description": "Template ID for this variation", "example": "template_variant_a" }, "metrics": { "$ref": "#/components/schemas/VariationMetrics" }, "template": { "type": "object", "nullable": true, "description": "Full template object (populated when with_templates=true)" } } }, "VariationMetrics": { "type": "object", "properties": { "recipients": { "type": "integer", "description": "Number of recipients" }, "delivered": { "type": "integer", "description": "Number of delivered messages" }, "opens": { "type": "integer", "description": "Number of opens" }, "clicks": { "type": "integer", "description": "Number of clicks" }, "bounced": { "type": "integer", "description": "Number of bounces" }, "complained": { "type": "integer", "description": "Number of complaints" }, "unsubscribed": { "type": "integer", "description": "Number of unsubscribes" } } }, "AudienceSettings": { "type": "object", "required": [ "list" ], "properties": { "list": { "type": "string", "description": "List ID to send to", "example": "newsletter" }, "segments": { "type": "array", "description": "Optional segment IDs to filter recipients", "items": { "type": "string" }, "example": [ "premium_users" ] }, "exclude_unsubscribed": { "type": "boolean", "description": "Whether to exclude unsubscribed contacts", "example": true } } }, "ScheduleSettings": { "type": "object", "description": "Schedule settings for a broadcast. Note: When a broadcast is first created,\nthese fields are empty/false. Use the /api/broadcasts.schedule endpoint to\nconfigure scheduling.\n", "properties": { "is_scheduled": { "type": "boolean", "description": "Whether the broadcast is scheduled (false after creation, set via broadcasts.schedule)", "example": false }, "scheduled_date": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$", "description": "Scheduled date in YYYY-MM-DD format", "example": "2024-03-15" }, "scheduled_time": { "type": "string", "pattern": "^\\d{2}:\\d{2}$", "description": "Scheduled time in HH:MM format", "example": "10:30" }, "timezone": { "type": "string", "description": "IANA timezone", "example": "America/New_York" }, "use_recipient_timezone": { "type": "boolean", "description": "Send at scheduled time in each recipient's timezone", "example": false } } }, "UTMParameters": { "type": "object", "properties": { "source": { "type": "string", "description": "UTM source parameter", "example": "newsletter" }, "medium": { "type": "string", "description": "UTM medium parameter", "example": "email" }, "campaign": { "type": "string", "description": "UTM campaign parameter", "example": "spring_2024" }, "term": { "type": "string", "description": "UTM term parameter" }, "content": { "type": "string", "description": "UTM content parameter" } } }, "CreateBroadcastRequest": { "type": "object", "required": [ "workspace_id", "name", "audience" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "name": { "type": "string", "description": "Name of the broadcast", "example": "Spring Newsletter 2024", "maxLength": 255 }, "audience": { "$ref": "#/components/schemas/AudienceSettings" }, "test_settings": { "$ref": "#/components/schemas/BroadcastTestSettings" }, "tracking_enabled": { "type": "boolean", "description": "Enable click and open tracking", "example": true }, "utm_parameters": { "$ref": "#/components/schemas/UTMParameters" }, "data_feed": { "$ref": "#/components/schemas/DataFeedSettings" }, "metadata": { "type": "object", "additionalProperties": true, "description": "Custom metadata for the broadcast" } } }, "UpdateBroadcastRequest": { "type": "object", "required": [ "workspace_id", "id", "name", "audience" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "id": { "type": "string", "description": "ID of the broadcast to update", "example": "broadcast_12345" }, "name": { "type": "string", "description": "Name of the broadcast", "example": "Spring Newsletter 2024", "maxLength": 255 }, "audience": { "$ref": "#/components/schemas/AudienceSettings" }, "schedule": { "$ref": "#/components/schemas/ScheduleSettings" }, "test_settings": { "$ref": "#/components/schemas/BroadcastTestSettings" }, "tracking_enabled": { "type": "boolean", "description": "Enable click and open tracking", "example": true }, "utm_parameters": { "$ref": "#/components/schemas/UTMParameters" }, "data_feed": { "$ref": "#/components/schemas/DataFeedSettings" }, "metadata": { "type": "object", "additionalProperties": true, "description": "Custom metadata for the broadcast" } } }, "ScheduleBroadcastRequest": { "type": "object", "required": [ "workspace_id", "id" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "id": { "type": "string", "description": "ID of the broadcast to schedule", "example": "broadcast_12345" }, "send_now": { "type": "boolean", "description": "Send immediately instead of scheduling", "example": false }, "scheduled_date": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$", "description": "Scheduled date in YYYY-MM-DD format (required if send_now=false)", "example": "2024-03-15" }, "scheduled_time": { "type": "string", "pattern": "^\\d{2}:\\d{2}$", "description": "Scheduled time in HH:MM format (required if send_now=false)", "example": "10:30" }, "timezone": { "type": "string", "description": "IANA timezone", "example": "America/New_York" }, "use_recipient_timezone": { "type": "boolean", "description": "Send at scheduled time in each recipient's timezone", "example": false } } }, "PauseBroadcastRequest": { "type": "object", "required": [ "workspace_id", "id" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "id": { "type": "string", "description": "ID of the broadcast to pause", "example": "broadcast_12345" } } }, "ResumeBroadcastRequest": { "type": "object", "required": [ "workspace_id", "id" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "id": { "type": "string", "description": "ID of the broadcast to resume", "example": "broadcast_12345" } } }, "CancelBroadcastRequest": { "type": "object", "required": [ "workspace_id", "id" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "id": { "type": "string", "description": "ID of the broadcast to cancel", "example": "broadcast_12345" } } }, "DeleteBroadcastRequest": { "type": "object", "required": [ "workspace_id", "id" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "id": { "type": "string", "description": "ID of the broadcast to delete", "example": "broadcast_12345" } } }, "SendToIndividualRequest": { "type": "object", "required": [ "workspace_id", "broadcast_id", "recipient_email" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "broadcast_id": { "type": "string", "description": "ID of the broadcast", "example": "broadcast_12345" }, "recipient_email": { "type": "string", "format": "email", "description": "Email address to send test to", "example": "test@example.com" }, "template_id": { "type": "string", "description": "Optional specific template variation to send", "example": "template_variant_a" } } }, "SelectWinnerRequest": { "type": "object", "required": [ "workspace_id", "id", "template_id" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "id": { "type": "string", "description": "ID of the broadcast", "example": "broadcast_12345" }, "template_id": { "type": "string", "description": "Template ID of the winning variation", "example": "template_variant_a" } } }, "BroadcastListResponse": { "type": "object", "properties": { "broadcasts": { "type": "array", "description": "List of broadcasts", "items": { "$ref": "#/components/schemas/Broadcast" } }, "total_count": { "type": "integer", "description": "Total number of broadcasts matching the query", "example": 45 } } }, "VariationResult": { "type": "object", "properties": { "template_id": { "type": "string", "description": "Template ID for this variation", "example": "template_variant_a" }, "template_name": { "type": "string", "description": "Template name", "example": "Variation A" }, "recipients": { "type": "integer", "description": "Total sent emails", "example": 1000 }, "delivered": { "type": "integer", "description": "Total delivered emails", "example": 980 }, "opens": { "type": "integer", "description": "Number of opens", "example": 450 }, "clicks": { "type": "integer", "description": "Number of clicks", "example": 120 }, "open_rate": { "type": "number", "format": "float", "description": "Open rate (opens / recipients)", "example": 0.45 }, "click_rate": { "type": "number", "format": "float", "description": "Click rate (clicks / recipients)", "example": 0.12 } } }, "TestResultsResponse": { "type": "object", "properties": { "broadcast_id": { "type": "string", "description": "ID of the broadcast", "example": "broadcast_12345" }, "status": { "type": "string", "description": "Current broadcast status", "example": "testing" }, "test_started_at": { "type": "string", "format": "date-time", "nullable": true, "description": "When the test started" }, "test_completed_at": { "type": "string", "format": "date-time", "nullable": true, "description": "When the test completed" }, "variation_results": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/VariationResult" }, "description": "Results for each variation, keyed by template_id" }, "recommended_winner": { "type": "string", "nullable": true, "description": "Recommended winning template ID based on metrics", "example": "template_variant_a" }, "winning_template": { "type": "string", "nullable": true, "description": "Selected winning template ID", "example": "template_variant_a" }, "is_auto_send_winner": { "type": "boolean", "description": "Whether winner will be automatically sent", "example": true } } }, "DataFeedHeader": { "type": "object", "required": [ "name", "value" ], "properties": { "name": { "type": "string", "description": "HTTP header name", "example": "Authorization" }, "value": { "type": "string", "description": "HTTP header value", "example": "Bearer token123" } } }, "GlobalFeedSettings": { "type": "object", "properties": { "enabled": { "type": "boolean", "description": "Whether the global data feed is enabled", "example": true }, "url": { "type": "string", "description": "URL endpoint to fetch global data from (must be HTTPS)", "example": "https://api.example.com/broadcast-data" }, "headers": { "type": "array", "description": "Custom HTTP headers to include in the request", "items": { "$ref": "#/components/schemas/DataFeedHeader" } } } }, "RecipientFeedSettings": { "type": "object", "properties": { "enabled": { "type": "boolean", "description": "Whether the per-recipient data feed is enabled", "example": true }, "url": { "type": "string", "description": "URL endpoint to fetch per-recipient data from (must be HTTPS)", "example": "https://api.example.com/recipient-data" }, "headers": { "type": "array", "description": "Custom HTTP headers to include in the request", "items": { "$ref": "#/components/schemas/DataFeedHeader" } } } }, "DataFeedSettings": { "type": "object", "description": "Configuration for external data feeds", "properties": { "global_feed": { "$ref": "#/components/schemas/GlobalFeedSettings" }, "global_feed_data": { "type": "object", "additionalProperties": true, "description": "Cached data from the global feed (populated after fetch)" }, "global_feed_fetched_at": { "type": "string", "format": "date-time", "nullable": true, "description": "When the global feed was last fetched" }, "recipient_feed": { "$ref": "#/components/schemas/RecipientFeedSettings" } } }, "RefreshGlobalFeedRequest": { "type": "object", "required": [ "workspace_id", "broadcast_id", "url" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "broadcast_id": { "type": "string", "description": "ID of the broadcast", "example": "broadcast_12345" }, "url": { "type": "string", "format": "uri", "description": "The feed URL to fetch data from", "example": "https://api.example.com/feed/global" }, "headers": { "type": "array", "description": "Optional custom headers to send with the request", "items": { "$ref": "#/components/schemas/DataFeedHeader" } } } }, "RefreshGlobalFeedResponse": { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the refresh was successful", "example": true }, "data": { "type": "object", "additionalProperties": true, "description": "The fetched data from the global feed" }, "fetched_at": { "type": "string", "format": "date-time", "description": "When the data was fetched" }, "error": { "type": "string", "description": "Error message if the refresh failed", "example": null } } }, "TestRecipientFeedRequest": { "type": "object", "required": [ "workspace_id", "broadcast_id", "url" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "broadcast_id": { "type": "string", "description": "ID of the broadcast", "example": "broadcast_12345" }, "contact_email": { "type": "string", "format": "email", "description": "Optional email of a specific contact to test with. If not provided, uses a random contact from the audience.", "example": "john@example.com" }, "url": { "type": "string", "format": "uri", "description": "The feed URL to fetch data from (must use HTTPS)", "example": "https://api.example.com/feed/recipient" }, "headers": { "type": "array", "description": "Optional custom headers to send with the request", "items": { "$ref": "#/components/schemas/DataFeedHeader" } } } }, "TestRecipientFeedResponse": { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the test was successful", "example": true }, "data": { "type": "object", "additionalProperties": true, "description": "The fetched data from the recipient feed" }, "fetched_at": { "type": "string", "format": "date-time", "description": "When the data was fetched" }, "error": { "type": "string", "description": "Error message if the test failed", "example": null }, "contact_email": { "type": "string", "format": "email", "description": "Email of the contact used for the test", "example": "john@example.com" } } }, "Template": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier for the template (alphanumeric, underscores, and hyphens only)", "example": "welcome_email", "maxLength": 32, "pattern": "^[a-zA-Z0-9_-]+$" }, "name": { "type": "string", "description": "Name of the template", "example": "Welcome Email", "maxLength": 32 }, "version": { "type": "integer", "format": "int64", "description": "Version number of the template", "example": 1 }, "channel": { "type": "string", "enum": [ "email", "web" ], "description": "Communication channel", "example": "email" }, "email": { "$ref": "#/components/schemas/EmailTemplate" }, "web": { "$ref": "#/components/schemas/WebTemplate" }, "category": { "type": "string", "enum": [ "marketing", "transactional", "welcome", "opt_in", "unsubscribe", "bounce", "blocklist", "blog", "other" ], "description": "Template category", "example": "transactional", "maxLength": 20 }, "template_macro_id": { "type": "string", "nullable": true, "description": "ID of the template macro (layout) to use" }, "integration_id": { "type": "string", "nullable": true, "description": "ID of the integration managing this template (e.g., Supabase)" }, "test_data": { "type": "object", "additionalProperties": true, "description": "Test data for template preview", "example": { "user_name": "John Doe", "action_url": "https://example.com/action" } }, "settings": { "type": "object", "additionalProperties": true, "description": "Channel-specific third-party settings" }, "created_at": { "type": "string", "format": "date-time", "description": "When the template was created" }, "updated_at": { "type": "string", "format": "date-time", "description": "When the template was last updated" }, "deleted_at": { "type": "string", "format": "date-time", "nullable": true, "description": "When the template was deleted (null if active)" } }, "required": [ "id", "name", "channel", "category" ] }, "EmailTemplate": { "type": "object", "properties": { "sender_id": { "type": "string", "description": "ID of the sender configuration to use", "example": "sender_123" }, "reply_to": { "type": "string", "format": "email", "description": "Reply-To email address", "example": "support@example.com" }, "subject": { "type": "string", "description": "Email subject line (supports Liquid templating)", "example": "Welcome, {{user_name}}!" }, "subject_preview": { "type": "string", "nullable": true, "description": "Preview text shown in email clients", "example": "Get started with your account" }, "compiled_preview": { "type": "string", "description": "Compiled HTML preview of the email" }, "visual_editor_tree": { "type": "object", "description": "MJML visual editor tree structure", "example": { "type": "mjml", "children": [] } }, "text": { "type": "string", "nullable": true, "description": "Plain text version of the email" } }, "required": [ "subject", "compiled_preview", "visual_editor_tree" ] }, "WebTemplate": { "type": "object", "properties": { "content": { "type": "object", "additionalProperties": true, "description": "Tiptap JSON content (source of truth for web templates)" }, "html": { "type": "string", "description": "Pre-rendered HTML for display" }, "plain_text": { "type": "string", "description": "Extracted text for search indexing" } }, "required": [ "content" ] }, "CreateTemplateRequest": { "type": "object", "required": [ "workspace_id", "id", "name", "channel", "category" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "id": { "type": "string", "description": "Unique identifier for the template (alphanumeric, underscores, and hyphens only)", "example": "welcome_email", "maxLength": 32, "pattern": "^[a-zA-Z0-9_-]+$" }, "name": { "type": "string", "description": "Name of the template", "example": "Welcome Email", "maxLength": 32 }, "channel": { "type": "string", "enum": [ "email", "web" ], "description": "Communication channel", "example": "email" }, "email": { "$ref": "#/components/schemas/EmailTemplate" }, "web": { "$ref": "#/components/schemas/WebTemplate" }, "category": { "type": "string", "enum": [ "marketing", "transactional", "welcome", "opt_in", "unsubscribe", "bounce", "blocklist", "blog", "other" ], "description": "Template category", "example": "transactional" }, "template_macro_id": { "type": "string", "nullable": true, "description": "ID of the template macro (layout) to use" }, "test_data": { "type": "object", "additionalProperties": true, "description": "Test data for template preview" }, "settings": { "type": "object", "additionalProperties": true, "description": "Channel-specific settings" } } }, "UpdateTemplateRequest": { "type": "object", "required": [ "workspace_id", "id", "name", "channel", "category" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "id": { "type": "string", "description": "ID of the template to update", "example": "welcome_email", "maxLength": 32 }, "name": { "type": "string", "description": "Name of the template", "example": "Welcome Email", "maxLength": 32 }, "channel": { "type": "string", "enum": [ "email", "web" ], "description": "Communication channel", "example": "email" }, "email": { "$ref": "#/components/schemas/EmailTemplate" }, "web": { "$ref": "#/components/schemas/WebTemplate" }, "category": { "type": "string", "enum": [ "marketing", "transactional", "welcome", "opt_in", "unsubscribe", "bounce", "blocklist", "blog", "other" ], "description": "Template category", "example": "transactional" }, "template_macro_id": { "type": "string", "nullable": true, "description": "ID of the template macro (layout) to use" }, "test_data": { "type": "object", "additionalProperties": true, "description": "Test data for template preview" }, "settings": { "type": "object", "additionalProperties": true, "description": "Channel-specific settings" } } }, "DeleteTemplateRequest": { "type": "object", "required": [ "workspace_id", "id" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "id": { "type": "string", "description": "ID of the template to delete", "example": "welcome_email" } } }, "CompileTemplateRequest": { "type": "object", "required": [ "workspace_id", "message_id", "visual_editor_tree" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "message_id": { "type": "string", "description": "Unique message ID for tracking", "example": "msg_abc123" }, "visual_editor_tree": { "type": "object", "description": "MJML visual editor tree structure (must have type 'mjml')", "additionalProperties": true }, "subject": { "type": "string", "description": "Optional email subject. When provided, it is rendered through the same\nLiquid engine the send path uses (with `test_data`) and the rendered\nresult is returned as `subject` in the response. Liquid processing is\nskipped when `preserve_liquid` is true, `channel` is `web`, or\n`test_data` is empty.\n", "example": "Hi {{ contact.first_name }}" }, "subject_preview": { "type": "string", "description": "Optional inbox preview text (the snippet shown after the subject in\nmost clients). Rendered through Liquid like `subject` and returned as\n`subject_preview` in the response.\n", "example": "Welcome {{ contact.first_name }}" }, "test_data": { "type": "object", "description": "Data to use for Liquid templating", "additionalProperties": true, "example": { "user_name": "John Doe", "action_url": "https://example.com/action" } }, "tracking_settings": { "$ref": "#/components/schemas/TrackingSettings" }, "channel": { "type": "string", "enum": [ "email", "web" ], "description": "Channel filter for block visibility" } } }, "CompileTemplateResponse": { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether compilation was successful" }, "mjml": { "type": "string", "description": "Generated MJML markup" }, "html": { "type": "string", "description": "Compiled HTML output" }, "subject": { "type": "string", "description": "Rendered email subject. Present only when the request included a\nnon-empty `subject`. Returned on both success and error paths so the\ncaller can display the rendered subject alongside any compilation\nerror.\n", "example": "Hi Pierre" }, "subject_preview": { "type": "string", "description": "Rendered inbox preview text. Present only when the request included a\nnon-empty `subject_preview`. Returned on both success and error paths.\n", "example": "Welcome Pierre" }, "error": { "type": "object", "description": "MJML compilation error details, if any", "properties": { "message": { "type": "string" } } } } }, "TrackingSettings": { "type": "object", "properties": { "enable_tracking": { "type": "boolean", "description": "Whether to enable click/open tracking" }, "tracking_mode": { "type": "string", "enum": [ "inherit", "disabled" ], "description": "Per-notification tri-state tracking preference. Absent or \"inherit\"\nfollows the workspace tracking flag (the workspace flag always acts\nas a kill-switch and cannot be overridden). \"disabled\" suppresses all\nrewriting for this notification — no click-tracking redirect, no open\npixel, and no UTM parameters — used for auth emails (e.g. Supabase\nmagic links) whose single-use URLs must never be modified. Update\nsemantics: an ABSENT tracking_mode field keeps the stored value (so\npartial edits cannot wipe an opt-out; an empty string is treated as\nabsent); an explicit \"inherit\" resets the notification to follow the\nworkspace flag; an explicit \"disabled\" opts it out. Note that the\nother tracking_settings fields (utm_*) are replaced wholesale on\nupdate — only tracking_mode has keep-when-absent semantics.\n" }, "endpoint": { "type": "string", "description": "API endpoint for tracking redirects" }, "utm_source": { "type": "string", "description": "UTM source parameter" }, "utm_medium": { "type": "string", "description": "UTM medium parameter" }, "utm_campaign": { "type": "string", "description": "UTM campaign parameter" }, "utm_content": { "type": "string", "description": "UTM content parameter" }, "utm_term": { "type": "string", "description": "UTM term parameter" }, "workspace_id": { "type": "string", "description": "Workspace ID for tracking" }, "message_id": { "type": "string", "description": "Message ID for tracking" } } }, "CustomEvent": { "type": "object", "required": [ "event_name", "external_id", "email" ], "properties": { "event_name": { "type": "string", "description": "Event type name (lowercase letters, numbers, underscores, dots, and slashes only)", "example": "orders/fulfilled", "maxLength": 100, "pattern": "^[a-z0-9_./-]+$" }, "external_id": { "type": "string", "description": "External system identifier for this event", "example": "shopify_order_12345", "maxLength": 255 }, "email": { "type": "string", "format": "email", "description": "Contact email address", "example": "customer@example.com" }, "properties": { "type": "object", "additionalProperties": true, "description": "JSONB event data with arbitrary structure", "example": { "order_total": 129.99, "product_name": "Premium Subscription", "quantity": 1 } }, "occurred_at": { "type": "string", "format": "date-time", "nullable": true, "description": "When the event occurred (allows backdating)", "example": "2023-05-15T14:30:00Z" }, "source": { "type": "string", "enum": [ "api", "integration", "import" ], "description": "Origin of the event (set automatically by server)", "example": "api", "default": "api" }, "integration_id": { "type": "string", "nullable": true, "description": "Optional reference to integration that created the event", "example": "shopify_integration_123" }, "goal_type": { "type": "string", "enum": [ "purchase", "subscription", "lead", "signup", "booking", "trial", "other" ], "nullable": true, "description": "Type of goal for conversion tracking. Required for goal_value to have meaning.", "example": "purchase" }, "goal_name": { "type": "string", "nullable": true, "maxLength": 100, "description": "Optional goal name for categorization (e.g., 'first_purchase', 'monthly_subscription')", "example": "first_purchase" }, "goal_value": { "type": "number", "format": "double", "nullable": true, "description": "Monetary value of the goal. Required for 'purchase' and 'subscription' goal types. Can be negative for refunds/chargebacks.", "example": 99.99 }, "deleted_at": { "type": "string", "format": "date-time", "nullable": true, "description": "Soft delete timestamp. Set to delete an event, set to null to restore.", "example": null }, "created_at": { "type": "string", "format": "date-time", "description": "When the event was created in the system", "example": "2023-05-15T14:30:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "When the event was last updated", "example": "2023-05-15T14:30:00Z" } } }, "ImportCustomEventsRequest": { "type": "object", "required": [ "workspace_id", "events" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "events": { "type": "array", "description": "Array of custom events to import (1-50 events)", "minItems": 1, "maxItems": 50, "items": { "type": "object", "required": [ "event_name", "external_id", "email" ], "properties": { "event_name": { "type": "string", "description": "Event type name", "example": "orders/fulfilled", "maxLength": 100, "pattern": "^[a-z0-9_./-]+$" }, "external_id": { "type": "string", "description": "External system identifier", "example": "shopify_order_12345", "maxLength": 255 }, "email": { "type": "string", "format": "email", "description": "Contact email address", "example": "customer@example.com" }, "properties": { "type": "object", "additionalProperties": true, "description": "Event data", "example": { "order_total": 129.99, "product_name": "Premium Subscription" } }, "occurred_at": { "type": "string", "format": "date-time", "description": "When the event occurred", "example": "2023-05-15T14:30:00Z" }, "source": { "type": "string", "enum": [ "api", "integration", "import" ], "description": "Origin of the event", "example": "api" }, "integration_id": { "type": "string", "description": "Integration reference", "example": "shopify_integration_123" }, "goal_type": { "type": "string", "enum": [ "purchase", "subscription", "lead", "signup", "booking", "trial", "other" ], "description": "Type of goal for conversion tracking", "example": "purchase" }, "goal_name": { "type": "string", "maxLength": 100, "description": "Optional goal name for categorization", "example": "first_purchase" }, "goal_value": { "type": "number", "format": "double", "description": "Monetary value (required for purchase/subscription, can be negative for refunds)", "example": 99.99 }, "deleted_at": { "type": "string", "format": "date-time", "description": "Soft delete timestamp", "example": null } } }, "example": [ { "event_name": "orders/fulfilled", "external_id": "shopify_order_12345", "email": "customer@example.com", "properties": { "order_total": 129.99, "product_name": "Premium Subscription" }, "occurred_at": "2023-05-15T14:30:00Z" }, { "event_name": "payment/succeeded", "external_id": "stripe_payment_67890", "email": "customer@example.com", "properties": { "amount": 129.99, "currency": "USD" }, "occurred_at": "2023-05-15T14:29:00Z" } ] } } }, "ImportCustomEventsResponse": { "type": "object", "properties": { "event_ids": { "type": "array", "description": "External IDs of successfully imported events", "items": { "type": "string" }, "example": [ "shopify_order_12345", "stripe_payment_67890" ] }, "count": { "type": "integer", "description": "Number of events created", "example": 2 } } }, "WebhookSubscription": { "type": "object", "description": "A webhook subscription that receives HTTP callbacks when events occur", "properties": { "id": { "type": "string", "description": "Unique identifier for the subscription", "example": "whsub_a1b2c3d4e5f6" }, "name": { "type": "string", "description": "Human-readable name for the subscription", "example": "Production Webhook" }, "url": { "type": "string", "format": "uri", "description": "The HTTPS URL to receive webhook events", "example": "https://api.example.com/webhooks/notifuse" }, "secret": { "type": "string", "description": "Secret key for signing webhook payloads (Standard Webhooks spec)", "example": "whsec_a1b2c3d4e5f6g7h8i9j0" }, "settings": { "$ref": "#/components/schemas/WebhookSubscriptionSettings" }, "event_types": { "type": "array", "description": "List of event types this subscription is subscribed to (flattened from settings for convenience)", "items": { "type": "string" }, "example": [ "contact.created", "contact.updated", "email.sent" ] }, "custom_event_filters": { "$ref": "#/components/schemas/CustomEventFilters", "description": "Optional filters for custom_event.* event types (flattened from settings for convenience)" }, "enabled": { "type": "boolean", "description": "Whether the subscription is currently active", "example": true }, "last_delivery_at": { "type": "string", "format": "date-time", "nullable": true, "description": "Timestamp of the last delivery attempt", "example": "2024-01-15T10:30:00Z" }, "created_at": { "type": "string", "format": "date-time", "description": "When the subscription was created", "example": "2024-01-01T00:00:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "When the subscription was last updated", "example": "2024-01-15T10:30:00Z" } } }, "WebhookDelivery": { "type": "object", "description": "A record of a webhook delivery attempt", "properties": { "id": { "type": "string", "description": "Unique identifier for the delivery", "example": "whdel_x1y2z3" }, "subscription_id": { "type": "string", "description": "ID of the subscription this delivery belongs to", "example": "whsub_a1b2c3d4e5f6" }, "event_type": { "type": "string", "description": "Type of event that triggered the delivery", "example": "contact.created" }, "payload": { "type": "object", "description": "The JSON payload sent in the webhook", "additionalProperties": true }, "status": { "type": "string", "enum": [ "pending", "delivering", "delivered", "failed" ], "description": "Current status of the delivery", "example": "delivered" }, "attempts": { "type": "integer", "description": "Number of delivery attempts made", "example": 1 }, "max_attempts": { "type": "integer", "description": "Maximum number of retry attempts", "example": 10 }, "next_attempt_at": { "type": "string", "format": "date-time", "nullable": true, "description": "When the next retry will be attempted", "example": "2024-01-15T10:35:00Z" }, "last_attempt_at": { "type": "string", "format": "date-time", "nullable": true, "description": "When the last attempt was made", "example": "2024-01-15T10:30:00Z" }, "delivered_at": { "type": "string", "format": "date-time", "nullable": true, "description": "When the delivery was successfully completed", "example": "2024-01-15T10:30:00Z" }, "last_response_status": { "type": "integer", "nullable": true, "description": "HTTP status code from the last attempt", "example": 200 }, "last_response_body": { "type": "string", "nullable": true, "description": "Response body from the last attempt (truncated)", "example": "{\"received\": true}" }, "last_error": { "type": "string", "nullable": true, "description": "Error message from the last failed attempt", "example": null }, "created_at": { "type": "string", "format": "date-time", "description": "When the delivery was created", "example": "2024-01-15T10:30:00Z" } } }, "WebhookEventType": { "type": "string", "description": "Available webhook event types", "enum": [ "contact.created", "contact.updated", "contact.deleted", "list.subscribed", "list.unsubscribed", "list.confirmed", "list.resubscribed", "list.bounced", "list.complained", "list.pending", "list.removed", "segment.joined", "segment.left", "email.sent", "email.delivered", "email.opened", "email.clicked", "email.bounced", "email.complained", "email.unsubscribed", "custom_event.created", "custom_event.updated", "custom_event.deleted" ] }, "CustomEventFilters": { "type": "object", "nullable": true, "description": "Optional filters for custom_event.* event types", "properties": { "goal_types": { "type": "array", "nullable": true, "description": "Filter by goal type (e.g., purchase, subscription, lead)", "items": { "type": "string" }, "example": [ "purchase", "subscription" ] }, "event_names": { "type": "array", "nullable": true, "description": "Filter by event name (e.g., orders/fulfilled, payment.succeeded)", "items": { "type": "string" }, "example": [ "orders/fulfilled", "payment.succeeded" ] } } }, "WebhookSubscriptionSettings": { "type": "object", "description": "Settings for webhook subscription", "properties": { "event_types": { "type": "array", "description": "List of event types this subscription is subscribed to", "items": { "type": "string" }, "example": [ "contact.created", "contact.updated", "email.sent" ] }, "custom_event_filters": { "$ref": "#/components/schemas/CustomEventFilters" } } }, "CreateWebhookSubscriptionRequest": { "type": "object", "required": [ "workspace_id", "name", "url", "event_types" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "name": { "type": "string", "description": "Human-readable name for the subscription", "example": "Production Webhook", "minLength": 1, "maxLength": 255 }, "url": { "type": "string", "format": "uri", "description": "The HTTPS URL to receive webhook events", "example": "https://api.example.com/webhooks/notifuse" }, "event_types": { "type": "array", "description": "List of event types to subscribe to", "items": { "type": "string" }, "minItems": 1, "example": [ "contact.created", "contact.updated" ] }, "custom_event_filters": { "$ref": "#/components/schemas/CustomEventFilters" } } }, "CreateWebhookSubscriptionResponse": { "type": "object", "properties": { "subscription": { "$ref": "#/components/schemas/WebhookSubscription" } } }, "UpdateWebhookSubscriptionRequest": { "type": "object", "required": [ "workspace_id", "id", "name", "url", "event_types" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "id": { "type": "string", "description": "The ID of the subscription to update", "example": "whsub_a1b2c3d4e5f6" }, "name": { "type": "string", "description": "Updated name", "example": "Production Webhook Updated" }, "url": { "type": "string", "format": "uri", "description": "Updated URL", "example": "https://api.example.com/webhooks/notifuse/v2" }, "event_types": { "type": "array", "description": "Updated list of event types", "items": { "type": "string" }, "example": [ "contact.created", "contact.updated", "contact.deleted" ] }, "custom_event_filters": { "$ref": "#/components/schemas/CustomEventFilters" }, "enabled": { "type": "boolean", "description": "Whether the subscription is enabled", "example": true } } }, "UpdateWebhookSubscriptionResponse": { "type": "object", "properties": { "subscription": { "$ref": "#/components/schemas/WebhookSubscription" } } }, "DeleteWebhookSubscriptionRequest": { "type": "object", "required": [ "workspace_id", "id" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "id": { "type": "string", "description": "The ID of the subscription to delete", "example": "whsub_a1b2c3d4e5f6" } } }, "ToggleWebhookSubscriptionRequest": { "type": "object", "required": [ "workspace_id", "id", "enabled" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "id": { "type": "string", "description": "The ID of the subscription", "example": "whsub_a1b2c3d4e5f6" }, "enabled": { "type": "boolean", "description": "Whether to enable or disable the subscription", "example": true } } }, "ToggleWebhookSubscriptionResponse": { "type": "object", "properties": { "subscription": { "$ref": "#/components/schemas/WebhookSubscription" } } }, "RegenerateWebhookSecretRequest": { "type": "object", "required": [ "workspace_id", "id" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "id": { "type": "string", "description": "The ID of the subscription", "example": "whsub_a1b2c3d4e5f6" } } }, "RegenerateWebhookSecretResponse": { "type": "object", "properties": { "subscription": { "$ref": "#/components/schemas/WebhookSubscription" } } }, "ListWebhookSubscriptionsResponse": { "type": "object", "properties": { "subscriptions": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookSubscription" } } } }, "GetWebhookSubscriptionResponse": { "type": "object", "properties": { "subscription": { "$ref": "#/components/schemas/WebhookSubscription" } } }, "ListWebhookDeliveriesResponse": { "type": "object", "properties": { "deliveries": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookDelivery" } }, "total": { "type": "integer", "description": "Total number of deliveries", "example": 150 }, "limit": { "type": "integer", "description": "Number of deliveries per page", "example": 20 }, "offset": { "type": "integer", "description": "Offset for pagination", "example": 0 } } }, "TestWebhookRequest": { "type": "object", "required": [ "workspace_id", "id" ], "properties": { "workspace_id": { "type": "string", "description": "The ID of the workspace", "example": "ws_1234567890" }, "id": { "type": "string", "description": "The ID of the subscription to test", "example": "whsub_a1b2c3d4e5f6" }, "event_type": { "type": "string", "description": "Optional event type to use for the test webhook payload", "example": "contact.created" } } }, "TestWebhookResponse": { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the test webhook was delivered successfully", "example": true }, "status_code": { "type": "integer", "description": "HTTP status code returned by the webhook endpoint", "example": 200 }, "response_body": { "type": "string", "description": "Response body from the webhook endpoint", "example": "{\"received\": true}" }, "error": { "type": "string", "nullable": true, "description": "Error message if the test failed", "example": null } } }, "ListWebhookEventTypesResponse": { "type": "object", "properties": { "event_types": { "type": "array", "items": { "type": "string" }, "example": [ "contact.created", "contact.updated", "contact.deleted", "list.subscribed", "list.unsubscribed", "email.sent", "email.delivered" ] } } }, "RootSigninRequest": { "type": "object", "description": "Request payload for root user programmatic signin using HMAC signature", "properties": { "email": { "type": "string", "format": "email", "description": "The root user's email address (must match one of the configured ROOT_EMAIL addresses)", "example": "admin@example.com" }, "timestamp": { "type": "integer", "format": "int64", "description": "Unix timestamp (seconds since epoch). Must be within 60 seconds of server time.", "example": 1735600000 }, "signature": { "type": "string", "description": "HMAC-SHA256 signature computed as: HMAC-SHA256(email + \":\" + timestamp, SECRET_KEY)\nThe signature should be hex-encoded.\n", "example": "a1b2c3d4e5f6..." } }, "required": [ "email", "timestamp", "signature" ] }, "RootSigninResponse": { "type": "object", "description": "Successful authentication response containing JWT token and user details", "properties": { "token": { "type": "string", "description": "JWT authentication token for subsequent API requests", "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }, "user": { "$ref": "#/components/schemas/User" }, "expires_at": { "type": "string", "format": "date-time", "description": "Token expiration timestamp", "example": "2025-01-01T12:00:00Z" } }, "required": [ "token", "user", "expires_at" ] }, "User": { "type": "object", "description": "User account information", "properties": { "id": { "type": "string", "description": "Unique user identifier", "example": "usr_1234567890" }, "email": { "type": "string", "format": "email", "description": "User's email address", "example": "admin@example.com" }, "name": { "type": "string", "description": "User's display name", "example": "Admin User" }, "language": { "type": "string", "description": "User's preferred locale for the console UI and system emails", "example": "en" }, "created_at": { "type": "string", "format": "date-time", "description": "Account creation timestamp", "example": "2025-01-01T00:00:00Z" }, "updated_at": { "type": "string", "format": "date-time", "description": "Last update timestamp", "example": "2025-01-01T00:00:00Z" } }, "required": [ "id", "email" ] } } } }