{"openapi":"3.0.0","paths":{"/api/v1/inbox/contacts":{"get":{"operationId":"InboxController_listContacts","summary":"List inbox contacts for copy into a campaign segment","description":"Read-only. Returns name, phone, bsuid, and username. Does not send messages.","parameters":[{"name":"status","required":false,"in":"query","schema":{"enum":["OPEN","CLOSED"],"type":"string"}},{"name":"assignee","required":false,"in":"query","description":"Conversation assignee user id","schema":{"type":"string"}},{"name":"lastMessageFrom","required":false,"in":"query","description":"Inclusive ISO-8601 lower bound on last message time","schema":{"type":"string"}},{"name":"lastMessageTo","required":false,"in":"query","description":"Inclusive ISO-8601 upper bound on last message time","schema":{"type":"string"}},{"name":"fields","required":false,"in":"query","description":"Comma-separated subset of name, phone, bsuid, username","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"default":50,"type":"number"},"description":"Page size. Defaults to 50, maximum 100."},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"},"description":"Page cursor returned by the previous response. Leave empty for the first page."}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxContactListDto"}}}}},"tags":["Inbox"],"security":[{"bearer":[]}]}},"/api/v1/inbox/channels":{"get":{"operationId":"InboxController_listChannels","summary":"List channels visible to this key","description":"An account key sees every channel. A user key sees only channels that user can open.","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InboxChannelSummaryDto"}}}}}},"tags":["Inbox"],"security":[{"bearer":[]}]}},"/api/v1/inbox/channels/{channelId}/assignees":{"get":{"operationId":"InboxController_listChannelAssignees","summary":"People who can be assigned on this channel","description":"The account owner, plus operators who already have this channel. Use the returned id as userId when assigning a conversation.","parameters":[{"name":"channelId","required":true,"in":"path","description":"Channel id from GET /inbox/channels","schema":{"example":"QAF261225002","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InboxAssigneeDto"}}}}},"404":{"description":"Channel not found or the key cannot see it"}},"tags":["Inbox"],"security":[{"bearer":[]}]}},"/api/v1/inbox/conversations":{"get":{"operationId":"InboxController_getDialogs","summary":"List conversations","description":"Newest lastMessageAt first. Pass pagination.nextCursor as cursor for the next page.","parameters":[{"name":"limit","required":false,"in":"query","description":"Page size. Default 50.","schema":{"example":50,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"pagination.nextCursor from the previous page (ISO lastMessageAt).","schema":{"type":"string"}},{"name":"channelId","required":false,"in":"query","description":"Limit to one channel.","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Conversation status.","schema":{"enum":["OPEN","CLOSED"],"type":"string"}},{"name":"unread","required":false,"in":"query","description":"true keeps only conversations with unread messages.","schema":{"type":"boolean"}},{"name":"tab","required":false,"in":"query","description":"mine_open: open and assigned to this key. unassigned: open and nobody assigned. all: no extra tab filter.","schema":{"enum":["mine_open","unassigned","all"],"type":"string"}},{"name":"assigneeId","required":false,"in":"query","description":"Only conversations assigned to this user id.","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxDialogListDto"}}}}},"tags":["Inbox"],"security":[{"bearer":[]}]}},"/api/v1/inbox/conversations/search":{"get":{"operationId":"InboxController_searchDialogs","summary":"Search conversations","description":"Matches contact name, phone, and message text in one channel. channelId is required. query must be at least 3 characters; a shorter query returns two empty lists.","parameters":[{"name":"query","required":true,"in":"query","description":"At least 3 characters.","schema":{"example":"7900","type":"string"}},{"name":"channelId","required":false,"in":"query","description":"Channel to search. Required.","schema":{"example":"QAF261225002","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxDialogSearchDto"}}}}},"tags":["Inbox"],"security":[{"bearer":[]}]}},"/api/v1/inbox/conversations/counts":{"get":{"operationId":"InboxController_getDialogCounts","summary":"Conversation counts","description":"mine_open and unassigned count only OPEN conversations. all counts every visible conversation.","parameters":[{"name":"channelId","required":false,"in":"query","description":"Limit the counts to one channel.","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxDialogCountsDto"}}}}},"tags":["Inbox"],"security":[{"bearer":[]}]}},"/api/v1/inbox/conversations/{conversationId}":{"get":{"operationId":"InboxController_getDialog","summary":"One conversation","description":"Includes the contact, assignee, and customer phone.","parameters":[{"name":"conversationId","required":true,"in":"path","description":"Conversation id","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxDialogDto"}}}},"404":{"description":"Conversation not found, or the key cannot see its channel"}},"tags":["Inbox"],"security":[{"bearer":[]}]}},"/api/v1/inbox/conversations/{conversationId}/messages":{"get":{"operationId":"InboxController_getMessages","summary":"Messages in a conversation","description":"Newest first. Omit kind, or pass kind=all, to include SYSTEM events (status, assignee, block, title) together with messages. kind=messages hides SYSTEM events. kind=system returns only SYSTEM events. Notes stay with messages. Pass nextCursor as cursor to load older rows of the same kind.","parameters":[{"name":"conversationId","required":true,"in":"path","description":"Conversation id","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Page size. Default 50.","schema":{"example":50,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"nextCursor from the previous page (ISO createdAt). Returns rows older than that instant, still filtered by kind.","schema":{"type":"string"}},{"name":"kind","required":false,"in":"query","description":"all (default when omitted): every row. messages: everything except SYSTEM. system: only SYSTEM.","schema":{"enum":["all","messages","system"],"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxMessageListDto"}}}},"404":{"description":"Conversation not found, or the key cannot see its channel"}},"tags":["Inbox"],"security":[{"bearer":[]}]}},"/api/v1/inbox/conversations/{conversationId}/assignee":{"patch":{"operationId":"InboxController_updateDialogAssignee","summary":"Assign, reassign, or clear the conversation assignee","description":"userId is the id from GET /api/v1/inbox/channels/{channelId}/assignees. That person must already be able to open this channel. null clears the assignee. Setting the same assignee does nothing and writes no system message. A real change writes one SYSTEM message.","parameters":[{"name":"conversationId","required":true,"in":"path","description":"Conversation id","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDialogAssigneeDto"}}}},"responses":{"200":{"description":"Updated conversation row.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxDialogDto"}}}},"404":{"description":"Conversation not found, the key cannot see the channel, or the user cannot be assigned on it"}},"tags":["Inbox"],"security":[{"bearer":[]}]}},"/api/v1/inbox/conversations/{conversationId}/status":{"patch":{"operationId":"InboxController_updateDialogStatus","summary":"Open or close a conversation","description":"Send status OPEN or CLOSED in the JSON body. The conversation id alone does not change anything. A change writes a SYSTEM message. The same status again returns 409.","parameters":[{"name":"conversationId","required":true,"in":"path","description":"Conversation id","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDialogStatusDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxDialogDto"}}}},"404":{"description":"Conversation not found, or the key cannot see its channel"},"409":{"description":"Conversation is already open, or already closed"}},"tags":["Inbox"],"security":[{"bearer":[]}]}},"/api/v1/inbox/conversations/{conversationId}/block":{"post":{"operationId":"InboxController_blockContact","summary":"Block the contact","description":"No body. Incoming messages from this contact are rejected. Writes a SYSTEM message. Blocking an already blocked contact returns 409.","parameters":[{"name":"conversationId","required":true,"in":"path","description":"Conversation id","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxDialogDto"}}}},"404":{"description":"Conversation not found, or the key cannot see its channel"},"409":{"description":"Contact is already blocked"}},"tags":["Inbox"],"security":[{"bearer":[]}]}},"/api/v1/inbox/conversations/{conversationId}/unblock":{"post":{"operationId":"InboxController_unblockContact","summary":"Unblock the contact","description":"No body. Messages can be sent and received again. Writes a SYSTEM message. Unblocking a contact that is not blocked returns 409.","parameters":[{"name":"conversationId","required":true,"in":"path","description":"Conversation id","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxDialogDto"}}}},"404":{"description":"Conversation not found, or the key cannot see its channel"},"409":{"description":"Contact is already unblocked"}},"tags":["Inbox"],"security":[{"bearer":[]}]}},"/api/v1/inbox/conversations/{conversationId}/title":{"patch":{"operationId":"InboxController_updateDialogTitle","summary":"Rename a conversation","description":"Body title replaces the conversation title and writes a SYSTEM message.","parameters":[{"name":"conversationId","required":true,"in":"path","description":"Conversation id","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDialogTitleDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxDialogDto"}}}},"404":{"description":"Conversation not found, or the key cannot see its channel"}},"tags":["Inbox"],"security":[{"bearer":[]}]}},"/api/v1/inbox/webhook":{"get":{"operationId":"InboxWebhookController_get","summary":"Read the account inbox webhook","description":"One HTTPS URL per account. The owner sets it here or in Settings → Developer → API Settings. A user key cannot. When inbox state changes, 1MSG POSTs `InboxWebhookEnvelope` to that URL.\n\nThis is not the channel webhook. Incoming messages and delivery statuses stay on the channel URL.\n\n### Delivery\n\n- `Content-Type`: `application/json`\n- `X-1msg-Event`: the type\n- `X-1msg-Delivery`: the id\n- `X-1msg-Signature`: `sha256=<hex HMAC of the raw body>`\n\nCompare the signature with HMAC-SHA256 over the exact request body with the signing secret. Reject a mismatch.\n\nDelivery does not change the API response. A failed POST is stored as `lastDeliveryStatus` and `lastDeliveryError`.\n\n### Events\n\n| Event | When | data fields |\n| --- | --- | --- |\n| `inbox.conversation.status_changed` | Conversation opened or closed. status is OPEN or CLOSED. | `conversationId`, `channelId`, `status`, `previousStatus`, `actorUserId` |\n| `inbox.conversation.assigned` | An assignee was set. assigneeUserId is the new assignee. | `conversationId`, `channelId`, `assigneeUserId`, `previousAssigneeUserId`, `actorUserId` |\n| `inbox.conversation.unassigned` | The assignee was cleared. assigneeUserId is null. | `conversationId`, `channelId`, `assigneeUserId`, `previousAssigneeUserId`, `actorUserId` |\n| `inbox.conversation.blocked` | The contact was blocked. Incoming messages are rejected. | `conversationId`, `channelId`, `actorUserId` |\n| `inbox.conversation.unblocked` | The contact was unblocked. | `conversationId`, `channelId`, `actorUserId` |\n| `inbox.conversation.title_changed` | The conversation title was renamed. | `conversationId`, `channelId`, `title`, `previousTitle`, `actorUserId` |\n| `inbox.user.invited` | The owner invited a user. They are not a member until they accept. | `inviteId`, `email`, `channelIds`, `actorUserId` |\n| `inbox.user.added` | The invited person accepted and is now an operator. | `memberId`, `userId`, `email`, `channelIds` |\n| `inbox.user.removed` | An operator was removed from the account. | `memberId`, `userId`, `actorUserId` |\n| `inbox.user.channels_changed` | The channels an operator can open were replaced. | `memberId`, `userId`, `channelIds`, `actorUserId` |\n| `inbox.user.invite_revoked` | A pending invite was cancelled before it was accepted. | `inviteId`, `email`, `actorUserId` |","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxWebhookViewDto"}}}}},"tags":["Inbox"],"security":[{"bearer":[]}]},"put":{"operationId":"InboxWebhookController_save","summary":"Set the account inbox webhook URL","description":"Creates the webhook and returns the signing secret once, or updates the URL and keeps the existing secret.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertInboxWebhookDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxWebhookSavedDto"}}}}},"tags":["Inbox"],"security":[{"bearer":[]}]},"delete":{"operationId":"InboxWebhookController_remove","summary":"Remove the account inbox webhook","description":"Later inbox changes are not delivered until a URL is saved again.","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxWebhookRemovedDto"}}}}},"tags":["Inbox"],"security":[{"bearer":[]}]}},"/api/v1/inbox/webhook/secret":{"post":{"operationId":"InboxWebhookController_rotate","summary":"Rotate the inbox webhook signing secret","description":"Returns the new secret once. The previous secret stops verifying deliveries immediately. 404 when no URL is saved.","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxWebhookSavedDto"}}}}},"tags":["Inbox"],"security":[{"bearer":[]}]}},"/api/v1/campaigns/segments":{"post":{"operationId":"CampaignSegmentsController_create","summary":"Create a segment","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCampaignSegmentDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignSegmentCreatedDto"}}}}},"tags":["Segments"],"security":[{"bearer":[]}],"description":"name is required, up to 200 characters. description is optional, up to 2000 characters. Returns the segment id used when creating a campaign."},"get":{"operationId":"CampaignSegmentsController_list","summary":"List segments","parameters":[{"name":"limit","required":false,"in":"query","description":"Page size. Defaults to 50, maximum 100.","schema":{"type":"string"}},{"name":"cursor","required":false,"in":"query","description":"nextCursor from the previous page. Leave empty for the first page.","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignSegmentPageDto"}}}}},"tags":["Segments"],"security":[{"bearer":[]}],"description":"Newest first. limit is the page size, default 50, maximum 100. cursor is the nextCursor from the previous page. Leave cursor empty for the first page."}},"/api/v1/campaigns/segments/{segmentId}/members":{"get":{"operationId":"CampaignSegmentsController_listMembers","summary":"List segment members","parameters":[{"name":"segmentId","required":true,"in":"path","schema":{"type":"string"},"description":"Segment id returned by create or list."},{"name":"limit","required":false,"in":"query","description":"Page size. Defaults to 50, maximum 100.","schema":{"type":"string"}},{"name":"cursor","required":false,"in":"query","description":"nextCursor from the previous page. Leave empty for the first page.","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignSegmentMemberPageDto"}}}}},"tags":["Segments"],"security":[{"bearer":[]}],"description":"limit is the page size, default 50, maximum 100. cursor is the nextCursor from the previous page."},"post":{"operationId":"CampaignSegmentsController_addMembers","summary":"Add segment members","description":"members is a non-empty list. Each item needs name. phone is E.164 or omitted. bsuid is the provider id, for example ab.abc123xyz, or omitted. One of phone or bsuid is required. A duplicate phone or BSUID in the segment is rejected. The segment cannot exceed 500 members. Each member may include attributes — a flat JSON object of string key-value pairs (max 50 keys, key up to 64 chars matching [a-zA-Z_][a-zA-Z0-9_]*, value up to 1024 chars, total JSON up to 10KB). Attributes are used for per-recipient template variable bindings.","parameters":[{"name":"segmentId","required":true,"in":"path","schema":{"type":"string"},"description":"Segment id returned by create or list."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddCampaignSegmentMembersDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignSegmentMemberBatchDto"}}}}},"tags":["Segments"],"security":[{"bearer":[]}]},"put":{"operationId":"CampaignSegmentsController_replaceMembers","summary":"Replace segment members","description":"Deletes every current member and inserts this list. The same name, phone, and bsuid rules apply as when adding members. The new list cannot exceed 500 members.","parameters":[{"name":"segmentId","required":true,"in":"path","schema":{"type":"string"},"description":"Segment id returned by create or list."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplaceCampaignSegmentMembersDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignSegmentMemberBatchDto"}}}}},"tags":["Segments"],"security":[{"bearer":[]}]},"delete":{"operationId":"CampaignSegmentsController_removeMembers","summary":"Remove segment members","parameters":[{"name":"segmentId","required":true,"in":"path","schema":{"type":"string"},"description":"Segment id returned by create or list."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoveCampaignSegmentMembersDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignSegmentMembersRemovedDto"}}}}},"tags":["Segments"],"security":[{"bearer":[]}],"description":"memberIds is a non-empty list of member ids from the member list. Other members stay."}},"/api/v1/campaigns/segments/{segmentId}/members/{memberId}":{"patch":{"operationId":"CampaignSegmentsController_patchMember","summary":"Update one segment member","parameters":[{"name":"segmentId","required":true,"in":"path","schema":{"type":"string"},"description":"Segment id returned by create or list."},{"name":"memberId","required":true,"in":"path","schema":{"type":"string"},"description":"Member id returned by the member list."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchCampaignSegmentMemberDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignSegmentMemberDto"}}}}},"tags":["Segments"],"security":[{"bearer":[]}],"description":"Send only the fields that change. phone must stay E.164. bsuid must stay in the provider format. The member still needs a phone or a BSUID after the update."}},"/api/v1/campaigns/segments/{segmentId}":{"get":{"operationId":"CampaignSegmentsController_get","summary":"Get a segment","parameters":[{"name":"segmentId","required":true,"in":"path","schema":{"type":"string"},"description":"Segment id returned by create or list."}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignSegmentDto"}}}}},"tags":["Segments"],"security":[{"bearer":[]}],"description":"segmentId is the id returned when the segment was created."},"patch":{"operationId":"CampaignSegmentsController_update","summary":"Update a segment","parameters":[{"name":"segmentId","required":true,"in":"path","schema":{"type":"string"},"description":"Segment id returned by create or list."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCampaignSegmentDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignSegmentDto"}}}}},"tags":["Segments"],"security":[{"bearer":[]}],"description":"Send only the fields that change. name up to 200 characters. description up to 2000 characters. segmentId is the id from create."},"delete":{"operationId":"CampaignSegmentsController_remove","summary":"Delete a segment","parameters":[{"name":"segmentId","required":true,"in":"path","schema":{"type":"string"},"description":"Segment id returned by create or list."}],"responses":{"204":{"description":""}},"tags":["Segments"],"security":[{"bearer":[]}],"description":"Deletes the segment and its members. Fails while a draft, sending, paused, or scheduled campaign still uses it."}},"/api/v1/campaigns/{campaignId}/analytics":{"get":{"operationId":"CampaignAnalyticsController_summary","summary":"Analytics summary","description":"Counts for the snapshot taken at send. dailyLimit is the channel tier, not a campaign setting. Rates are fractions from 0 to 1.","parameters":[{"name":"campaignId","required":true,"in":"path","schema":{"type":"string"},"description":"Campaign id returned by create or list."}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignAnalyticsSummaryDto"}}}}},"tags":["Analytics"],"security":[{"bearer":[]}]}},"/api/v1/campaigns/{campaignId}/analytics/recipients":{"get":{"operationId":"CampaignAnalyticsController_recipients","summary":"Recipient analytics","description":"One row per recipient. filter is a comma-separated list of sent, delivered, read, replied, failed, skipped, or cancelled. filter=clicked is rejected; use filter=replied with replyType=button. fields limits the columns. conversationId is the Inbox dialog. providerConversationId is the provider chat id. messageId and providerMessageId are the provider message id. limit max 100. cursor is nextCursor.","parameters":[{"name":"campaignId","required":true,"in":"path","schema":{"type":"string"},"description":"Campaign id returned by create or list."},{"name":"filter","required":false,"in":"query","description":"Comma-separated: sent, delivered, read, replied, failed, skipped, cancelled. filter=clicked is rejected — use replied with replyType=button.","schema":{"type":"string"}},{"name":"replied","required":false,"in":"query","description":"true keeps only people who replied. false keeps people who did not.","schema":{"enum":["true","false"],"type":"string"}},{"name":"replyType","required":false,"in":"query","description":"button keeps button taps. text keeps free-text replies.","schema":{"enum":["button","text"],"type":"string"}},{"name":"buttonId","required":false,"in":"query","description":"One template button id. Use with replyType=button.","schema":{"type":"string"}},{"name":"reason","required":false,"in":"query","description":"Exact skip or fail reason from the errors feed.","schema":{"type":"string"}},{"name":"fields","required":false,"in":"query","description":"Comma-separated columns to return. Include providerConversationId and providerMessageId when you need the provider ids. conversationId is the Inbox dialog id. messageId is the provider message id.","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Page size, from 1 to 100. Default 50.","schema":{"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"nextCursor from the previous page. Leave empty for the first page.","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignAnalyticsRecipientPageDto"}}}}},"tags":["Analytics"],"security":[{"bearer":[]}]}},"/api/v1/campaigns/{campaignId}/analytics/replies":{"get":{"operationId":"CampaignAnalyticsController_replies","summary":"Reply feed","parameters":[{"name":"campaignId","required":true,"in":"path","schema":{"type":"string"},"description":"Campaign id returned by create or list."},{"name":"replyType","required":false,"in":"query","description":"button keeps button taps. text keeps free-text replies. Omit to return both.","schema":{"enum":["button","text"],"type":"string"}},{"name":"buttonId","required":false,"in":"query","description":"One template button id.","schema":{"type":"string"}},{"name":"phone","required":false,"in":"query","description":"E.164 phone of one recipient.","schema":{"type":"string"}},{"name":"bsuid","required":false,"in":"query","description":"Provider BSUID of one recipient, for example ab.abc123xyz.","schema":{"type":"string"}},{"name":"dateFrom","required":false,"in":"query","description":"ISO-8601 start, inclusive, for example 2026-11-01T00:00:00Z.","schema":{"type":"string"}},{"name":"dateTo","required":false,"in":"query","description":"ISO-8601 end, inclusive, for example 2026-11-02T00:00:00Z.","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Page size, from 1 to 100. Default 50.","schema":{"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"nextCursor from the previous page. Leave empty for the first page.","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignAnalyticsRepliesDto"}}}}},"tags":["Analytics"],"security":[{"bearer":[]}],"description":"replyType is button or text. buttonId filters one button. phone and bsuid filter one recipient. dateFrom and dateTo are ISO-8601. providerConversationId is the provider chat id. messageId and providerMessageId are the provider message id."}},"/api/v1/campaigns/{campaignId}/analytics/errors":{"get":{"operationId":"CampaignAnalyticsController_errors","summary":"Errors by reason","parameters":[{"name":"campaignId","required":true,"in":"path","schema":{"type":"string"},"description":"Campaign id returned by create or list."},{"name":"recipientsLimit","required":false,"in":"query","description":"Recipients shown per reason. Default 20, max 100.","schema":{"type":"number"}},{"name":"type","required":false,"in":"query","description":"failed keeps send errors. skipped keeps recipients that were not sent. Omit to return both.","schema":{"enum":["failed","skipped"],"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignAnalyticsErrorsDto"}}}}},"tags":["Analytics"],"security":[{"bearer":[]}],"description":"Groups failed and skipped recipients by reason. type is failed or skipped. recipientsLimit is how many recipients to include per reason, default 20, maximum 100. Each recipient includes providerConversationId and providerMessageId."}},"/api/v1/campaigns":{"post":{"operationId":"CampaignsController_create","summary":"Create a campaign draft","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCampaignDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignResponseDto"}}}}},"tags":["Campaigns"],"security":[{"bearer":[]}],"description":"name is the campaign title. channelId is the channel that will send. segmentId is the audience. content.mode is template or text. For a template set content.templateName, content.language, and content.params (the sendTemplate array). content.messageSendTtlSeconds is optional, in seconds, and sits beside params. For text set content.text. status, if sent, must be draft. content.bindings maps template slot keys to data source refs (e.g. {\"1\": \"segment.name\", \"2\": \"segment.attributes.order_id\"}). Bindings work with the variables path only; combining params and bindings returns 400. content.onMissing controls behavior when a binding cannot resolve for a recipient; default is skip_recipient."},"get":{"operationId":"CampaignsController_list","summary":"List campaigns","description":"Newest first, for the whole account. channelId limits the list to those channels. Repeat the parameter or pass a comma-separated list. Omit channelId to return every channel. limit defaults to 50, maximum 100. cursor is nextCursor from the previous page.","parameters":[{"name":"limit","required":false,"in":"query","description":"Page size. Defaults to 50, maximum 100.","schema":{"type":"string"}},{"name":"cursor","required":false,"in":"query","description":"nextCursor from the previous page. Leave empty for the first page.","schema":{"type":"string"}},{"name":"channelId","required":false,"in":"query","description":"Channel id. Repeat the parameter or pass a comma-separated list. Omit to list every channel.","schema":{"type":"array","items":{}}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignPageDto"}}}}},"tags":["Campaigns"],"security":[{"bearer":[]}]}},"/api/v1/campaigns/{campaignId}/preview":{"get":{"operationId":"CampaignsController_previewCampaign","summary":"Preview a campaign","parameters":[{"name":"campaignId","required":true,"in":"path","schema":{"type":"string"},"description":"Campaign id returned by create or list."}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignPreviewDto"}}}}},"tags":["Campaigns"],"security":[{"bearer":[]}],"description":"Counts recipients and how many are outside the 24-hour window. tierDailyLimit is the channel tier. No price and no cost are returned. Nothing is sent."}},"/api/v1/campaigns/{campaignId}/send":{"post":{"operationId":"CampaignsController_send","summary":"Send or schedule a campaign","description":"Copies the segment into the send snapshot. scheduledAt is a future ISO-8601 instant with Z or a numeric offset. Omit it or send null to start now. Template sends pause when the channel tier for the rolling 24 hours is used up. There is no separate per-day field.","parameters":[{"name":"campaignId","required":true,"in":"path","schema":{"type":"string"},"description":"Campaign id returned by create or list."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendCampaignDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignResponseDto"}}}}},"tags":["Campaigns"],"security":[{"bearer":[]}]}},"/api/v1/campaigns/{campaignId}/schedule":{"patch":{"operationId":"CampaignsController_schedule","summary":"Change the scheduled time","parameters":[{"name":"campaignId","required":true,"in":"path","schema":{"type":"string"},"description":"Campaign id returned by create or list."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCampaignScheduleDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignResponseDto"}}}}},"tags":["Campaigns"],"security":[{"bearer":[]}],"description":"scheduledAt is a new future ISO-8601 instant with Z or a numeric offset. Only a campaign that is already scheduled can be moved."}},"/api/v1/campaigns/{campaignId}/unschedule":{"post":{"operationId":"CampaignsController_unschedule","summary":"Return a scheduled campaign to draft","parameters":[{"name":"campaignId","required":true,"in":"path","schema":{"type":"string"},"description":"Campaign id returned by create or list."}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignResponseDto"}}}}},"tags":["Campaigns"],"security":[{"bearer":[]}],"description":"Clears scheduledAt and sets status back to draft. No body."}},"/api/v1/campaigns/{campaignId}/pause":{"post":{"operationId":"CampaignsController_pause","summary":"Pause a sending campaign","parameters":[{"name":"campaignId","required":true,"in":"path","schema":{"type":"string"},"description":"Campaign id returned by create or list."}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignResponseDto"}}}}},"tags":["Campaigns"],"security":[{"bearer":[]}],"description":"Stops taking new recipients from the queue. No body. Resume continues the same snapshot."}},"/api/v1/campaigns/{campaignId}/resume":{"post":{"operationId":"CampaignsController_resume","summary":"Resume a paused campaign","parameters":[{"name":"campaignId","required":true,"in":"path","schema":{"type":"string"},"description":"Campaign id returned by create or list."}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignResponseDto"}}}}},"tags":["Campaigns"],"security":[{"bearer":[]}],"description":"Continues the same snapshot. No body. The daily cap is still the channel tier."}},"/api/v1/campaigns/{campaignId}/complete":{"post":{"operationId":"CampaignsController_complete","summary":"Complete a campaign","parameters":[{"name":"campaignId","required":true,"in":"path","schema":{"type":"string"},"description":"Campaign id returned by create or list."}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignResponseDto"}}}}},"tags":["Campaigns"],"security":[{"bearer":[]}],"description":"Marks a sending or paused campaign completed and drops recipients that were not sent. No body."}},"/api/v1/campaigns/{campaignId}/test":{"post":{"operationId":"CampaignsController_test","summary":"Send one test","description":"Sends the draft content to one recipient and does not change campaign status or analytics. Provide exactly one of phone (E.164) or bsuid (provider format). A provider rejection is an error, not an accepted send. conversationId is the Inbox dialog. messageId and providerMessageId are the same provider message id, or null when the provider accepted the send without an id.","parameters":[{"name":"campaignId","required":true,"in":"path","schema":{"type":"string"},"description":"Campaign id returned by create or list."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignTestSendDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignTestSendResponseDto"}}}}},"tags":["Campaigns"],"security":[{"bearer":[]}]}},"/api/v1/campaigns/{campaignId}":{"get":{"operationId":"CampaignsController_get","summary":"Get a campaign","parameters":[{"name":"campaignId","required":true,"in":"path","schema":{"type":"string"},"description":"Campaign id returned by create or list."}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignResponseDto"}}}}},"tags":["Campaigns"],"security":[{"bearer":[]}],"description":"campaignId is the id from create. dailyLimit is the channel tier for a rolling 24 hours. It is not a value you set. scheduledAt is the future send time, or null."},"patch":{"operationId":"CampaignsController_update","summary":"Update a draft campaign","parameters":[{"name":"campaignId","required":true,"in":"path","schema":{"type":"string"},"description":"Campaign id returned by create or list."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCampaignDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignResponseDto"}}}}},"tags":["Campaigns"],"security":[{"bearer":[]}],"description":"Only a draft can be changed. Send at least one of name, channelId, segmentId, or content. content follows the same template and text rules as create. content.bindings and content.onMissing can be set or cleared. Combining params and bindings returns 400."}}},"info":{"title":"1MSG Platform API","description":"WhatsApp Inbox API is an HTTP API for 1MSG Inbox. Your code does in Inbox what an operator does on the Platform: list conversations, assign them, open and close them, and block a contact. Your team keeps working in Inbox as usual and sees every change your code makes. Each action leaves a system message in the chat.\n\nThe two APIs split the work. The [WhatsApp Business API](https://docs.1msg.io/) sends and receives messages. Inbox API manages who handles a conversation, what state it is in, and what has changed. You still reply to customers through the WhatsApp Business API. Incoming messages and delivery statuses still arrive at your channel webhook. Inbox events go to their own webhook, and each one is signed.\n\n## API key\n\nSign in at [platform.1msg.io](https://platform.1msg.io). Open Settings → Developer → API Settings, generate a key, and copy it. The full key is shown once.\n\nSend it on every request:\n\n```\nAuthorization: Bearer 1msg_live_••••••••\n```\n\nThe key belongs to a user and has that user's permissions. When the key is issued, choose Inbox, Campaigns, or both. It sees the same channels, and every action is made on that user's behalf. For all channels, the account owner creates a key for themselves. To work within a teammate's permissions, create a key for that teammate.","version":"1.0","contact":{}},"tags":[{"name":"Inbox","description":"Inbox API manages Inbox over HTTP: read conversations and messages, assign users, change conversation status, and block contacts. It also delivers notifications about actions in Inbox. It does not send messages."},{"name":"Segments","description":"Create a segment, then add people. Each member needs a name and a phone in E.164 or a BSUID."},{"name":"Campaigns","description":"Create a draft, set the template or text, preview, then send or schedule. The daily template cap is the channel tier, not a field on the campaign."},{"name":"Analytics","description":"Read the send snapshot: who was reached, what they replied, and why a send failed. conversationId is the Inbox dialog. providerConversationId is the provider chat id. messageId and providerMessageId are the same provider message id."}],"servers":[{"url":"https://api.1msg.io","description":"Production"},{"url":"https://api.stage.1msg.io","description":"Staging"}],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"API key","type":"http","description":"Key issued in Settings → Developer → API key. Inbox methods need the Inbox scope. Campaigns methods need the Campaigns scope."}},"schemas":{"InboxContactListDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/InboxContactItemDto"}},"nextCursor":{"type":"string","nullable":true}},"required":["items","nextCursor"]},"InboxChannelSummaryDto":{"type":"object","properties":{"id":{"type":"string","example":"QAF261225002"},"name":{"type":"string","example":"QA FMF"},"status":{"type":"string","enum":["INCOMPLETE","PENDING","ACTIVE","SUSPENDED","DISCONNECTED","DELETED"],"example":"ACTIVE"}},"required":["id","name","status"]},"InboxAssigneeDto":{"type":"object","properties":{"id":{"type":"string","example":"b2bb82f0-2253-4e05-b955-a21f3d699caa"},"name":{"type":"string","example":"QA Stage"},"avatar":{"type":"string","nullable":true,"example":null},"role":{"type":"string","enum":["OWNER","OPERATOR"],"example":"OPERATOR"}},"required":["id","name","role"]},"InboxDialogListDto":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InboxDialogDto"}},"pagination":{"$ref":"#/components/schemas/InboxDialogPageDto"}},"required":["data","pagination"]},"InboxDialogSearchDto":{"type":"object","properties":{"contacts":{"description":"Conversations matched by contact name or phone.","type":"array","items":{"$ref":"#/components/schemas/InboxDialogDto"}},"messages":{"description":"Conversations matched by message text. A conversation already listed in contacts is not repeated here.","type":"array","items":{"$ref":"#/components/schemas/InboxDialogDto"}}},"required":["contacts","messages"]},"InboxDialogCountsDto":{"type":"object","properties":{"mine_open":{"type":"number","description":"Open conversations assigned to the key actor.","example":0},"unassigned":{"type":"number","description":"Open conversations with no assignee.","example":0},"all":{"type":"number","description":"All conversations visible to the key, any status.","example":1}},"required":["mine_open","unassigned","all"]},"InboxDialogDto":{"type":"object","properties":{"id":{"type":"string"},"channelId":{"type":"string","description":"Channel id, for example QAF261225002"},"contactId":{"type":"string"},"status":{"type":"string","enum":["OPEN","CLOSED","ASSIGNED","RESOLVED","BLOCKED"],"description":"The key sets only OPEN or CLOSED. Other values can appear on older rows."},"assignedTo":{"type":"string","nullable":true,"description":"User id of the assignee. Null when unassigned."},"assignedUser":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/InboxUserDto"}]},"lastMessageAt":{"type":"string","nullable":true,"format":"date-time"},"isUnread":{"type":"boolean"},"tags":{"type":"array","items":{"type":"string"}},"lastMessagePreview":{"type":"string","nullable":true},"lastMessageType":{"type":"string","nullable":true},"lastMessageDirection":{"type":"string","nullable":true,"enum":["INBOUND","OUTBOUND"]},"lastMessageStatus":{"type":"string","nullable":true},"unreadCount":{"type":"number","example":0},"isBlocked":{"type":"boolean"},"title":{"type":"string","nullable":true,"description":"Custom title. Null until renamed."},"lastCustomerMessageAt":{"type":"string","nullable":true,"format":"date-time","description":"Last inbound customer message. Used for the WhatsApp service window."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"contact":{"nullable":true,"description":"Present on GET conversation, list, and search. Absent on block, title, and status writes.","allOf":[{"$ref":"#/components/schemas/InboxContactDto"}]},"channelType":{"type":"string","example":"WABA","description":"Present on reads."},"customerPhone":{"type":"string","nullable":true,"description":"Customer phone taken from the contact."}},"required":["id","channelId","contactId","status","isUnread","tags","unreadCount","isBlocked","createdAt","updatedAt"]},"InboxMessageListDto":{"type":"object","properties":{"messages":{"description":"Newest first. Includes SYSTEM events.","type":"array","items":{"$ref":"#/components/schemas/InboxMessageDto"}},"nextCursor":{"type":"string","nullable":true,"format":"date-time","description":"Pass back as cursor to load older messages. Null on the last page."},"hasMore":{"type":"boolean"}},"required":["messages","hasMore"]},"UpdateDialogAssigneeDto":{"type":"object","properties":{"userId":{"type":"string","nullable":true,"example":"66c21609-01ed-4f83-8058-9b6ac090db3f","description":"User id from GET /api/v1/inbox/channels/{channelId}/assignees. Null clears the assignee. The same assignee is a no-op."}},"required":["userId"]},"UpdateDialogStatusDto":{"type":"object","properties":{"status":{"type":"string","enum":["OPEN","CLOSED"],"example":"CLOSED","description":"OPEN reopens the conversation. CLOSED closes it. Repeating the current value returns 409."}},"required":["status"]},"UpdateDialogTitleDto":{"type":"object","properties":{"title":{"type":"string","example":"Billing question","description":"Replaces the dialog title. A system message records the change."}},"required":["title"]},"InboxWebhookViewDto":{"type":"object","properties":{"url":{"type":"string","nullable":true,"example":"https://example.com/1msg/inbox","description":"HTTPS URL that receives POST deliveries. Null when no webhook is saved."},"secretPrefix":{"type":"string","nullable":true,"example":"whsec_abc123","description":"First 12 characters of the signing secret. The full secret is not returned here."},"createdAt":{"type":"string","nullable":true,"format":"date-time"},"updatedAt":{"type":"string","nullable":true,"format":"date-time"},"lastDeliveryAt":{"type":"string","nullable":true,"format":"date-time","description":"When the last delivery attempt finished."},"lastDeliveryStatus":{"type":"number","nullable":true,"example":200,"description":"HTTP status from the last delivery. Null when the request did not get a response."},"lastDeliveryError":{"type":"string","nullable":true,"description":"Short error from the last failed delivery."},"events":{"description":"Every event this webhook can send. Message and delivery-status events stay on the channel webhook.","type":"array","items":{"$ref":"#/components/schemas/InboxWebhookEventExampleDto"}},"envelope":{"description":"Example of the JSON body 1MSG POSTs. data matches events[].example for the type in the body.","allOf":[{"$ref":"#/components/schemas/InboxWebhookEnvelopeDto"}]}},"required":["events","envelope"]},"UpsertInboxWebhookDto":{"type":"object","properties":{"url":{"type":"string","example":"https://example.com/1msg/inbox","description":"HTTPS endpoint. 1MSG POSTs a JSON event here. Credentials in the URL are rejected."}},"required":["url"]},"InboxWebhookSavedDto":{"type":"object","properties":{"url":{"type":"string","nullable":true,"example":"https://example.com/1msg/inbox","description":"HTTPS URL that receives POST deliveries. Null when no webhook is saved."},"secretPrefix":{"type":"string","nullable":true,"example":"whsec_abc123","description":"First 12 characters of the signing secret. The full secret is not returned here."},"createdAt":{"type":"string","nullable":true,"format":"date-time"},"updatedAt":{"type":"string","nullable":true,"format":"date-time"},"lastDeliveryAt":{"type":"string","nullable":true,"format":"date-time","description":"When the last delivery attempt finished."},"lastDeliveryStatus":{"type":"number","nullable":true,"example":200,"description":"HTTP status from the last delivery. Null when the request did not get a response."},"lastDeliveryError":{"type":"string","nullable":true,"description":"Short error from the last failed delivery."},"events":{"description":"Every event this webhook can send. Message and delivery-status events stay on the channel webhook.","type":"array","items":{"$ref":"#/components/schemas/InboxWebhookEventExampleDto"}},"envelope":{"description":"Example of the JSON body 1MSG POSTs. data matches events[].example for the type in the body.","allOf":[{"$ref":"#/components/schemas/InboxWebhookEnvelopeDto"}]},"secret":{"type":"string","nullable":true,"example":"whsec_example_secret","description":"Full signing secret. Present only when the webhook is created or the secret is rotated. Store it. Later reads return secretPrefix only."},"created":{"type":"boolean","description":"True when this call created the webhook. False when it updated the URL or rotated the secret."}},"required":["events","envelope","created"]},"InboxWebhookRemovedDto":{"type":"object","properties":{"removed":{"type":"boolean","example":true}},"required":["removed"]},"CreateCampaignSegmentDto":{"type":"object","properties":{"name":{"type":"string","description":"Segment name, up to 200 characters.","example":"April buyers"},"description":{"type":"string","description":"Optional note, up to 2000 characters."}},"required":["name"]},"CampaignSegmentCreatedDto":{"type":"object","properties":{"id":{"type":"string","description":"Segment id.","example":"cm3segment01"},"name":{"type":"string","description":"Segment name, up to 200 characters.","example":"April buyers"},"description":{"type":"string","nullable":true,"description":"Optional note, up to 2000 characters, or null when none was stored.","example":"People who bought in April"},"createdAt":{"type":"string","format":"date-time","description":"When the segment was created.","example":"2026-11-01T09:00:00.000Z"}},"required":["id","name","description","createdAt"]},"CampaignSegmentPageDto":{"type":"object","properties":{"items":{"description":"Segments on this page, newest first.","type":"array","items":{"$ref":"#/components/schemas/CampaignSegmentListItemDto"}},"nextCursor":{"type":"string","nullable":true,"description":"Cursor for the next page, or null on the last page.","example":null}},"required":["items","nextCursor"]},"CampaignSegmentMemberPageDto":{"type":"object","properties":{"items":{"description":"Members on this page, newest first.","type":"array","items":{"$ref":"#/components/schemas/CampaignSegmentMemberDto"}},"nextCursor":{"type":"string","nullable":true,"description":"Cursor for the next page, or null on the last page.","example":null}},"required":["items","nextCursor"]},"AddCampaignSegmentMembersDto":{"type":"object","properties":{"members":{"description":"Non-empty list. Each item needs name and a phone or a BSUID. A duplicate phone or BSUID in the segment is rejected. The segment cannot exceed 500 members.","type":"array","items":{"$ref":"#/components/schemas/CampaignSegmentMemberInputDto"}}},"required":["members"]},"CampaignSegmentMemberBatchDto":{"type":"object","properties":{"items":{"description":"Members written by this request.","type":"array","items":{"$ref":"#/components/schemas/CampaignSegmentMemberDto"}}},"required":["items"]},"ReplaceCampaignSegmentMembersDto":{"type":"object","properties":{"members":{"description":"Replaces every current member. Same name, phone, and bsuid rules as when adding members. An empty list clears the segment. The new list cannot exceed 500 members.","type":"array","items":{"$ref":"#/components/schemas/CampaignSegmentMemberInputDto"}}},"required":["members"]},"RemoveCampaignSegmentMembersDto":{"type":"object","properties":{"memberIds":{"description":"Member ids from the member list. Other members stay.","example":["mem_1"],"type":"array","items":{"type":"string"}}},"required":["memberIds"]},"CampaignSegmentMembersRemovedDto":{"type":"object","properties":{"removed":{"type":"number","description":"How many members were deleted.","example":2}},"required":["removed"]},"PatchCampaignSegmentMemberDto":{"type":"object","properties":{"name":{"type":"string","description":"New name, up to 200 characters."},"phone":{"type":"string","description":"E.164 phone, for example +15551234567. After the update the member still needs a phone or a BSUID."},"bsuid":{"type":"string","description":"Provider BSUID, for example ab.abc123xyz. A trailing @lid is stored without it."},"attributes":{"type":"object","additionalProperties":{"type":"string"},"nullable":true,"description":"Flat JSON object of string key-value pairs. Set to null to clear. Same validation rules as when adding members."}}},"CampaignSegmentMemberDto":{"type":"object","properties":{"id":{"type":"string","description":"Member id.","example":"cm3member01"},"name":{"type":"string","description":"Member name.","example":"Ana"},"phone":{"type":"string","nullable":true,"description":"Phone in E.164, or null when the member is stored by BSUID.","example":"+15551234567"},"bsuid":{"type":"string","nullable":true,"description":"Provider BSUID without a trailing @lid, or null when the member is stored by phone.","example":"ab.abc123xyz"},"attributes":{"type":"object","additionalProperties":{"type":"string"},"nullable":true,"description":"Arbitrary key-value data for template variable bindings, or null.","example":{"order_id":"ORD-1001"}}},"required":["id","name","phone","bsuid","attributes"]},"CampaignSegmentDto":{"type":"object","properties":{"id":{"type":"string","description":"Segment id.","example":"cm3segment01"},"name":{"type":"string","description":"Segment name, up to 200 characters.","example":"April buyers"},"description":{"type":"string","nullable":true,"description":"Optional note, up to 2000 characters, or null when none was stored."},"memberCount":{"type":"number","description":"How many people are in the segment.","example":12},"createdAt":{"type":"string","format":"date-time","description":"When the segment was created.","example":"2026-11-01T09:00:00.000Z"},"updatedAt":{"type":"string","format":"date-time","description":"When the segment was last updated.","example":"2026-11-01T09:00:00.000Z"}},"required":["id","name","description","memberCount","createdAt","updatedAt"]},"UpdateCampaignSegmentDto":{"type":"object","properties":{"name":{"type":"string","description":"New name, up to 200 characters. Send only the fields that change."},"description":{"type":"string","description":"New note, up to 2000 characters."}}},"CampaignAnalyticsSummaryDto":{"type":"object","properties":{"campaignId":{"type":"string","description":"Campaign id.","example":"cm3campaign01"},"status":{"type":"string","enum":["draft","sending","pause","completed","failed","scheduled"],"description":"Campaign status."},"recipients":{"type":"number","description":"Recipients in the send snapshot.","example":12},"sent":{"type":"number","description":"Recipients whose status is sent, delivered, or read.","example":10},"delivered":{"type":"number","description":"Recipients whose status is delivered or read.","example":8},"read":{"type":"number","description":"Recipients whose status is read.","example":4},"failed":{"type":"number","description":"Recipients whose status is failed.","example":1},"skipped":{"type":"number","description":"Recipients whose status is skipped.","example":1},"cancelled":{"type":"number","description":"Recipients removed from the queue before send.","example":0},"queued":{"type":"number","description":"Recipients whose status is queued or leasing.","example":0},"replied":{"type":"number","description":"Recipients who sent at least one reply.","example":2},"textReplies":{"type":"number","description":"Recipients who sent at least one text reply.","example":1},"clicks":{"type":"number","description":"Button replies in the snapshot.","example":3},"uniqueClicks":{"type":"number","description":"Recipients who clicked at least one button.","example":2},"rates":{"description":"Shares of recipients, from 0 to 1, rounded to 4 decimal places. Each rate is 0 when there are no recipients.","allOf":[{"$ref":"#/components/schemas/CampaignAnalyticsRatesDto"}]},"buttons":{"description":"Button clicks grouped by button id.","type":"array","items":{"$ref":"#/components/schemas/CampaignAnalyticsButtonDto"}},"queuedRemaining":{"type":"number","description":"Recipients still waiting to be sent.","example":0},"sentThisPortion":{"type":"number","description":"Template sends already started in the current tier window.","example":0},"dailyLimit":{"type":"number","nullable":true,"description":"How many template sends this channel may start in a rolling 24 hours, or null when the tier is unknown or unlimited.","example":1000},"nextPortionAt":{"type":"string","nullable":true,"format":"date-time","description":"When the next template portion can start, or null when a portion is not waiting.","example":null}},"required":["campaignId","status","recipients","sent","delivered","read","failed","skipped","cancelled","queued","replied","textReplies","clicks","uniqueClicks","rates","buttons","queuedRemaining","sentThisPortion","dailyLimit","nextPortionAt"]},"CampaignAnalyticsRecipientPageDto":{"type":"object","properties":{"items":{"description":"Recipients on this page. When the fields query is set, each item contains only the named keys.","type":"array","items":{"$ref":"#/components/schemas/CampaignAnalyticsRecipientDto"}},"nextCursor":{"type":"string","nullable":true,"description":"Cursor for the next page, or null on the last page.","example":null}},"required":["items","nextCursor"]},"CampaignAnalyticsRepliesDto":{"type":"object","properties":{"campaignId":{"type":"string","description":"Campaign id.","example":"cm3campaign01"},"totalReplies":{"type":"number","description":"Reply count for the whole campaign, not just this page.","example":4},"uniqueRepliers":{"type":"number","description":"How many recipients replied at least once in the whole campaign.","example":3},"items":{"description":"Replies on this page, oldest first.","type":"array","items":{"$ref":"#/components/schemas/CampaignAnalyticsReplyItemDto"}},"nextCursor":{"type":"string","nullable":true,"description":"Cursor for the next page, or null on the last page.","example":null}},"required":["campaignId","totalReplies","uniqueRepliers","items","nextCursor"]},"CampaignAnalyticsErrorsDto":{"type":"object","properties":{"campaignId":{"type":"string","description":"Campaign id.","example":"cm3campaign01"},"items":{"description":"Errors grouped by reason, code, title, and type.","type":"array","items":{"$ref":"#/components/schemas/CampaignAnalyticsErrorGroupDto"}}},"required":["campaignId","items"]},"CreateCampaignDto":{"type":"object","properties":{"name":{"type":"string","description":"Campaign title shown in the list.","example":"Spring promo"},"channelId":{"type":"string","description":"Id of the channel that sends. The key must be allowed to use this channel."},"segmentId":{"type":"string","description":"Segment id from POST /campaigns/segments. Members are copied when you send."},"content":{"description":"template or text. For a template set templateName, language, and params.","allOf":[{"$ref":"#/components/schemas/CampaignContentDto"}]},"status":{"type":"string","enum":["draft"],"description":"Only draft is accepted. Omit to store draft."}},"required":["name","channelId","segmentId","content"]},"CampaignResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Campaign id.","example":"cm3campaign01"},"name":{"type":"string","description":"Campaign title.","example":"April restock"},"channelId":{"type":"string","description":"Channel that sends the campaign.","example":"cm3channel01"},"segmentId":{"type":"string","description":"Segment used as the audience.","example":"cm3segment01"},"status":{"type":"string","enum":["draft","sending","pause","completed","failed","scheduled"],"description":"Campaign status."},"content":{"description":"Template or session text stored on the campaign.","oneOf":[{"$ref":"#/components/schemas/CampaignTextContentResponseDto"},{"$ref":"#/components/schemas/CampaignTemplateParamsContentResponseDto"},{"$ref":"#/components/schemas/CampaignTemplateVariablesContentResponseDto"}]},"sentAt":{"type":"string","nullable":true,"format":"date-time","description":"When sending started, or null if it has not started.","example":"2026-11-01T09:00:00.000Z"},"scheduledAt":{"type":"string","nullable":true,"format":"date-time","description":"UTC instant for a scheduled send, or null.","example":"2026-11-01T09:00:00.000Z"},"queuedRemaining":{"type":"number","description":"Recipients still waiting to be sent.","example":0},"sentThisPortion":{"type":"number","description":"Template sends already started in the current tier window.","example":0},"dailyLimit":{"type":"number","nullable":true,"description":"How many template sends this channel may start in a rolling 24 hours. Taken from the channel tier (waba_info.current_limit), not from a campaign setting. Null when the tier is unknown or unlimited. Session text is not counted.","example":1000},"nextPortionAt":{"type":"string","nullable":true,"format":"date-time","description":"When the next template portion can start after the tier window is full. Null when a portion is not waiting.","example":null},"createdAt":{"type":"string","format":"date-time","description":"When the campaign was created.","example":"2026-11-01T09:00:00.000Z"},"updatedAt":{"type":"string","format":"date-time","description":"When the campaign was last updated.","example":"2026-11-01T09:00:00.000Z"}},"required":["id","name","channelId","segmentId","status","content","sentAt","scheduledAt","queuedRemaining","sentThisPortion","dailyLimit","nextPortionAt","createdAt","updatedAt"]},"CampaignPageDto":{"type":"object","properties":{"items":{"description":"Campaigns on this page, newest first.","type":"array","items":{"$ref":"#/components/schemas/CampaignResponseDto"}},"nextCursor":{"type":"string","nullable":true,"description":"Cursor for the next page, or null on the last page.","example":null}},"required":["items","nextCursor"]},"CampaignPreviewDto":{"type":"object","properties":{"campaignId":{"type":"string","description":"Campaign id.","example":"cm3campaign01"},"segmentId":{"type":"string","description":"Segment id used as the audience.","example":"cm3segment01"},"contentMode":{"type":"string","enum":["template","text"],"description":"Whether the campaign sends a template or session text."},"recipientCount":{"type":"number","description":"Members in the segment.","example":12},"closedWindowCount":{"type":"number","description":"Members outside the 24-hour window.","example":3},"tierDailyLimit":{"type":"number","nullable":true,"description":"How many template sends this channel may start in a rolling 24 hours. Taken from the channel tier, not from a field you set. Null when the tier is unknown or unlimited.","example":1000},"exceedsTierDailyLimit":{"type":"boolean","description":"True when a template send would pass the channel tier.","example":false},"warnings":{"description":"Warnings for this preview. Nothing is sent.","type":"array","items":{"$ref":"#/components/schemas/CampaignPreviewWarningDto"}}},"required":["campaignId","segmentId","contentMode","recipientCount","closedWindowCount","tierDailyLimit","exceedsTierDailyLimit","warnings"]},"SendCampaignDto":{"type":"object","properties":{"scheduledAt":{"type":"string","nullable":true,"description":"Future ISO-8601 instant with a Z or a numeric offset, for example 2026-11-01T09:00:00Z. Omit or null to start now. There is no per-day field. Template sends use the channel tier."}}},"UpdateCampaignScheduleDto":{"type":"object","properties":{"scheduledAt":{"type":"string","description":"New future ISO-8601 instant with a Z or a numeric offset, for example 2026-11-02T09:00:00Z. Required. Only a campaign that is already scheduled can be moved."}},"required":["scheduledAt"]},"CampaignTestSendDto":{"type":"object","properties":{"phone":{"type":"string","description":"E.164 phone, for example +15551234567. Send exactly one of phone or bsuid. Does not change campaign status or analytics."},"bsuid":{"type":"string","description":"Provider BSUID, for example ab.abc123xyz. A trailing @lid is accepted. Send exactly one of phone or bsuid."}}},"CampaignTestSendResponseDto":{"type":"object","properties":{"accepted":{"type":"boolean","description":"Always true when the test was accepted.","example":true},"campaignId":{"type":"string","description":"Campaign id.","example":"cm3campaign01"},"campaignStatus":{"type":"string","enum":["draft","sending","pause","completed","failed","scheduled"],"description":"Campaign status after the test. A test does not change it."},"excludedFromAnalytics":{"type":"boolean","description":"Always true. This send is left out of analytics.","example":true},"conversationId":{"type":"string","nullable":true,"description":"Inbox conversation id, or null when the provider did not return one.","example":"cm3dialog01"},"messageId":{"type":"string","nullable":true,"description":"Provider message id, or null when the provider accepted the send without an id.","example":"wamid.HBgM"},"providerMessageId":{"type":"string","nullable":true,"description":"Same value as messageId.","example":"wamid.HBgM"},"phone":{"type":"string","description":"E.164 phone. Present when the test was sent to a phone. Exactly one of phone or bsuid is returned.","example":"+15551234567"},"bsuid":{"type":"string","description":"Provider BSUID. Present when the test was sent to a BSUID. Exactly one of phone or bsuid is returned.","example":"ab.abc123xyz"}},"required":["accepted","campaignId","campaignStatus","excludedFromAnalytics","conversationId","messageId","providerMessageId"]},"UpdateCampaignDto":{"type":"object","properties":{"name":{"type":"string","description":"New title. Send at least one of name, channelId, segmentId, or content. Only a draft can be changed."},"channelId":{"type":"string","description":"Another channel this account owns."},"segmentId":{"type":"string","description":"Another segment id. The new members are copied when you send."},"content":{"description":"Replaces the whole content object. Same template and text rules as create.","allOf":[{"$ref":"#/components/schemas/CampaignContentDto"}]}}},"InboxContactItemDto":{"type":"object","properties":{"name":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"bsuid":{"type":"string","nullable":true},"username":{"type":"string","nullable":true}},"required":["name","phone","bsuid","username"]},"InboxDialogPageDto":{"type":"object","properties":{"hasMore":{"type":"boolean"},"nextCursor":{"type":"string","nullable":true,"format":"date-time","description":"Pass this back as cursor. It is the lastMessageAt of the last conversation on this page."},"limit":{"type":"number","example":50}},"required":["hasMore","limit"]},"InboxUserDto":{"type":"object","properties":{"id":{"type":"string","example":"b2bb82f0-2253-4e05-b955-a21f3d699caa"},"name":{"type":"string","example":"QA Stage"},"avatar":{"type":"string","nullable":true,"example":null}},"required":["id","name"]},"InboxContactDto":{"type":"object","properties":{"id":{"type":"string"},"phoneNumber":{"type":"string","example":"79001234567"},"name":{"type":"string","nullable":true},"avatar":{"type":"string","nullable":true}},"required":["id","phoneNumber"]},"InboxMessageDto":{"type":"object","properties":{"id":{"type":"string"},"conversationId":{"type":"string"},"channelId":{"type":"string"},"direction":{"type":"string","enum":["INBOUND","OUTBOUND"]},"type":{"type":"string","enum":["TEXT","IMAGE","VIDEO","AUDIO","DOCUMENT","LOCATION","LOCATION_REQUEST","CONTACT","TEMPLATE","SYSTEM","NOTE"],"description":"SYSTEM is an inbox event (status, assignee, block, title), not a chat message."},"content":{"type":"string"},"mediaUrl":{"type":"string","nullable":true},"mediaType":{"type":"string","nullable":true},"fileName":{"type":"string","nullable":true},"fileSize":{"type":"number","nullable":true},"mediaDuration":{"type":"number","nullable":true},"thumbnailUrl":{"type":"string","nullable":true},"templateName":{"type":"string","nullable":true},"templateLanguage":{"type":"string","nullable":true},"status":{"type":"string","enum":["PENDING","SENT","DELIVERED","READ","FAILED"]},"externalId":{"type":"string","nullable":true,"description":"Channel message id."},"sentAt":{"type":"string","nullable":true,"format":"date-time"},"deliveredAt":{"type":"string","nullable":true,"format":"date-time"},"readAt":{"type":"string","nullable":true,"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"systemEventSource":{"type":"string","description":"Set on SYSTEM events started by an operator."},"systemEventOperatorName":{"type":"string"},"systemEventOperatorEmail":{"type":"string"},"assignmentEvent":{"$ref":"#/components/schemas/InboxAssignmentEventDto"},"author":{"nullable":true,"description":"User who sent an outbound message.","allOf":[{"$ref":"#/components/schemas/InboxUserDto"}]},"quotedMessage":{"$ref":"#/components/schemas/InboxQuotedMessageDto"},"latitude":{"type":"number","description":"Set when type is LOCATION."},"longitude":{"type":"number","description":"Set when type is LOCATION."}},"required":["id","conversationId","channelId","direction","type","content","status","createdAt"]},"InboxWebhookEventExampleDto":{"type":"object","properties":{"type":{"type":"string","example":"inbox.conversation.status_changed"},"description":{"type":"string","example":"Conversation opened or closed. status is OPEN or CLOSED."},"example":{"type":"object","additionalProperties":true,"description":"Fields inside the delivered event data object for this type.","example":{"conversationId":"d94a047f-5984-42af-9f89-0f26c7e70ef1","channelId":"QAF261225002","status":"CLOSED","previousStatus":"OPEN","actorUserId":"b2bb82f0-2253-4e05-b955-a21f3d699caa"}}},"required":["type","description","example"]},"InboxWebhookEnvelopeDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Delivery id. Also sent as the X-1msg-Delivery header."},"type":{"type":"string","example":"inbox.conversation.status_changed","description":"Event name. Also sent as the X-1msg-Event header."},"createdAt":{"type":"string","format":"date-time"},"data":{"type":"object","additionalProperties":true,"description":"Event fields. Shape depends on type. See events[].example on GET /inbox/webhook."}},"required":["id","type","createdAt","data"]},"CampaignSegmentListItemDto":{"type":"object","properties":{"id":{"type":"string","description":"Segment id.","example":"cm3segment01"},"name":{"type":"string","description":"Segment name, up to 200 characters.","example":"April buyers"},"description":{"type":"string","nullable":true,"description":"Optional note, up to 2000 characters, or null when none was stored."},"memberCount":{"type":"number","description":"How many people are in the segment.","example":12}},"required":["id","name","description","memberCount"]},"CampaignSegmentMemberInputDto":{"type":"object","properties":{"name":{"type":"string","description":"Person name, up to 200 characters.","example":"Ana"},"phone":{"type":"string","description":"E.164 phone, for example +15551234567. Required when bsuid is omitted."},"bsuid":{"type":"string","description":"Provider BSUID, for example ab.abc123xyz. A trailing @lid is accepted and stored without it. Phone or BSUID is required."},"attributes":{"type":"object","additionalProperties":{"type":"string"},"example":{"order_id":"ORD-1001","city":"São Paulo"},"description":"Flat JSON object of string key-value pairs for per-recipient data. Max 50 keys, key up to 64 chars matching [a-zA-Z_][a-zA-Z0-9_]*, value up to 1024 chars, total JSON up to 10KB. Used with template variable bindings."}},"required":["name"]},"CampaignAnalyticsRatesDto":{"type":"object","properties":{"sent":{"type":"number","description":"Share of recipients counted as sent, delivered, or read.","example":0.5},"delivery":{"type":"number","description":"Share of recipients counted as delivered or read.","example":0.4},"read":{"type":"number","description":"Share of recipients counted as read.","example":0.25},"reply":{"type":"number","description":"Share of recipients who replied.","example":0.1},"click":{"type":"number","description":"Share of recipients who clicked a button.","example":0.05},"failed":{"type":"number","description":"Share of recipients counted as failed.","example":0}},"required":["sent","delivery","read","reply","click","failed"]},"CampaignAnalyticsButtonDto":{"type":"object","properties":{"id":{"type":"string","description":"Button id from the template reply.","example":"shop"},"title":{"type":"string","description":"Button title, or the button id when no title was stored.","example":"Shop"},"clicks":{"type":"number","description":"How many times this button was clicked.","example":4},"uniqueClicks":{"type":"number","description":"How many recipients clicked this button.","example":3}},"required":["id","title","clicks","uniqueClicks"]},"CampaignAnalyticsRecipientDto":{"type":"object","properties":{"phone":{"type":"string","nullable":true,"description":"Phone in E.164, or null when the recipient is stored by BSUID.","example":"+15551234567"},"bsuid":{"type":"string","nullable":true,"description":"Provider BSUID, or null when the recipient is stored by phone.","example":"ab.abc123xyz"},"name":{"type":"string","description":"Recipient name.","example":"Ana"},"conversationId":{"type":"string","nullable":true,"description":"Inbox conversation id, or null when none is linked.","example":"cm3dialog01"},"providerConversationId":{"type":"string","nullable":true,"description":"Provider chat id: phone digits plus @c.us, otherwise the BSUID plus @lid, or null.","example":"15551234567@c.us"},"messageId":{"type":"string","nullable":true,"description":"Provider message id, or null before the provider accepts the send.","example":"wamid.HBgM"},"providerMessageId":{"type":"string","nullable":true,"description":"Same value as messageId.","example":"wamid.HBgM"},"status":{"type":"string","enum":["queued","leasing","sent","delivered","read","failed","skipped","cancelled"],"description":"Snapshot delivery status."},"sentAt":{"type":"string","nullable":true,"format":"date-time","description":"When the message was sent, or null.","example":"2026-11-01T09:00:00.000Z"},"deliveredAt":{"type":"string","nullable":true,"format":"date-time","description":"When the message was delivered, or null.","example":"2026-11-01T09:00:00.000Z"},"readAt":{"type":"string","nullable":true,"format":"date-time","description":"When the message was read, or null.","example":"2026-11-01T09:00:00.000Z"},"replies":{"description":"Replies from this recipient, oldest first.","type":"array","items":{"$ref":"#/components/schemas/CampaignAnalyticsRecipientReplyDto"}},"error":{"type":"object","nullable":true,"description":"Error details, or null when the recipient has no error code, title, or failed time. When present, code, title, and failedAt are always included.","properties":{"code":{"type":"string","nullable":true,"description":"Provider or skip error code, or null when none was stored."},"title":{"type":"string","nullable":true,"description":"Error title, or null when none was stored."},"failedAt":{"type":"string","nullable":true,"format":"date-time","description":"When the send failed or was skipped, or null when no time was stored.","example":"2026-11-01T09:00:00.000Z"}}}},"required":["phone","bsuid","name","conversationId","providerConversationId","messageId","providerMessageId","status","sentAt","deliveredAt","readAt","replies","error"]},"CampaignAnalyticsReplyItemDto":{"type":"object","properties":{"type":{"type":"string","enum":["button","text"],"description":"button for a template quick reply, or text inside the 24-hour window."},"buttonId":{"type":"string","nullable":true,"description":"Button id, or null for a text reply.","example":"shop"},"text":{"type":"string","nullable":true,"description":"Reply text or button title, or null when none was stored."},"phone":{"type":"string","nullable":true,"description":"Phone in E.164, or null when the recipient is stored by BSUID.","example":"+15551234567"},"bsuid":{"type":"string","nullable":true,"description":"Provider BSUID, or null when the recipient is stored by phone.","example":"ab.abc123xyz"},"name":{"type":"string","description":"Recipient name.","example":"Ana"},"conversationId":{"type":"string","nullable":true,"description":"Inbox conversation id, or null when none is linked.","example":"cm3dialog01"},"providerConversationId":{"type":"string","nullable":true,"description":"Provider chat id: phone digits plus @c.us, otherwise the BSUID plus @lid, or null.","example":"15551234567@c.us"},"receivedAt":{"type":"string","format":"date-time","description":"When the reply was received.","example":"2026-11-01T09:00:00.000Z"},"messageId":{"type":"string","description":"Provider message id of the reply.","example":"wamid.HBgM"},"providerMessageId":{"type":"string","description":"Same value as messageId.","example":"wamid.HBgM"}},"required":["type","buttonId","text","phone","bsuid","name","conversationId","providerConversationId","receivedAt","messageId","providerMessageId"]},"CampaignAnalyticsErrorGroupDto":{"type":"object","properties":{"reason":{"type":"string","description":"Stored error reason. Groups without a reason are omitted.","example":"closed_window"},"code":{"type":"string","nullable":true,"description":"Provider or skip error code, or null when none was stored."},"title":{"type":"string","nullable":true,"description":"Error title, or null when none was stored."},"type":{"type":"string","enum":["failed","skipped"],"description":"failed is a provider failure. skipped was not sent."},"count":{"type":"number","description":"Recipients in this group.","example":2},"share":{"type":"number","description":"Share of all campaign recipients in this group, from 0 to 1, rounded to 4 decimal places.","example":0.1667},"recipients":{"description":"Recipients in this group, up to recipientsLimit.","type":"array","items":{"$ref":"#/components/schemas/CampaignAnalyticsErrorRecipientDto"}},"hasMore":{"type":"boolean","description":"True when more recipients share this reason than recipientsLimit returned.","example":false}},"required":["reason","code","title","type","count","share","recipients","hasMore"]},"CampaignContentDto":{"type":"object","properties":{"mode":{"type":"string","enum":["template","text"],"description":"template sends a WABA template. text sends session text and only reaches people inside the 24-hour window."},"templateName":{"type":"string","description":"WABA template name. Required when mode is template."},"language":{"type":"string","description":"Template language code, for example en or pt_BR. Required when mode is template."},"variables":{"type":"object","additionalProperties":{"type":"string"},"example":{"1":"Ana"},"description":"Flat body placeholders only, for example { \"1\": \"Ana\" }. A numeric key fills the body. Header, buttons, and carousel are not filled here — use params. Ignored when params is set."},"params":{"type":"array","description":"Preferred template fill. The same array sendTemplate accepts. Each item is a component with type (header, body, button, carousel, or a newer WABA type). The array is forwarded as-is, including a header image link. When this is set, variables is ignored. An empty array is valid.","example":[{"type":"header","parameters":[{"type":"image","image":{"link":"https://example.com/image.jpg"}}]},{"type":"body","parameters":[{"type":"text","text":"Ana"}]}]},"messageSendTtlSeconds":{"type":"number","example":86400,"description":"How many seconds WhatsApp keeps trying to deliver this template. Same field as sendTemplate messageSendTtlSeconds. It sits beside params, not inside the params array. Omit it to use the template default."},"bindings":{"type":"object","additionalProperties":{"type":"string"},"example":{"1":"segment.name","2":"segment.attributes.order_id"},"description":"Maps template slot keys to data source refs. Only works with the variables path (not params). Keys follow the same format as variables: numeric for body, header_N, button_url_N. Values are source references like segment.name or segment.attributes.<key>. When set alongside params, returns 400."},"onMissing":{"type":"string","enum":["skip_recipient"],"default":"skip_recipient","description":"What to do when a binding cannot be resolved for a recipient. skip_recipient (default): skip the recipient and record the reason."},"text":{"type":"string","description":"Session text. Required when mode is text. Not counted against the channel tier."}},"required":["mode"]},"CampaignTextContentResponseDto":{"type":"object","properties":{"mode":{"type":"string","enum":["text"],"example":"text","description":"Session text sent only inside the 24-hour window."},"text":{"type":"string","description":"Session text body. Empty when none was stored.","example":"Hello"}},"required":["mode","text"]},"CampaignTemplateParamsContentResponseDto":{"type":"object","properties":{"mode":{"type":"string","enum":["template"],"example":"template","description":"Approved WABA template."},"templateName":{"type":"string","description":"WABA template name. Empty when none was stored.","example":"order_update"},"language":{"type":"string","description":"Template language code. Empty when none was stored.","example":"en"},"params":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"object","additionalProperties":true}]},"description":"Template params stored for sendTemplate. Each item is a string or an object."},"messageSendTtlSeconds":{"type":"number","example":86400,"description":"Seconds WhatsApp keeps trying to deliver this template. Omitted when the template default is used."}},"required":["mode","templateName","language","params"]},"CampaignTemplateVariablesContentResponseDto":{"type":"object","properties":{"mode":{"type":"string","enum":["template"],"example":"template","description":"Approved WABA template."},"templateName":{"type":"string","description":"WABA template name. Empty when none was stored.","example":"order_update"},"language":{"type":"string","description":"Template language code. Empty when none was stored.","example":"en"},"variables":{"type":"object","additionalProperties":{"type":"string"},"example":{"1":"Ana"},"description":"Flat template placeholders. Present when params were not stored."},"messageSendTtlSeconds":{"type":"number","example":86400,"description":"Seconds WhatsApp keeps trying to deliver this template. Omitted when the template default is used."}},"required":["mode","templateName","language","variables"]},"CampaignPreviewWarningDto":{"type":"object","properties":{"code":{"type":"string","enum":["closed_window_skipped","session_consumes_free_window","exceeds_tier_daily_limit","recipient_cap_exceeded"],"description":"Warning code."},"message":{"type":"string","description":"Human-readable warning.","example":"Closed-window recipients will be skipped."}},"required":["code","message"]},"InboxAssignmentEventDto":{"type":"object","properties":{"kind":{"type":"string","enum":["assign","unassign"]},"actor":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/InboxUserDto"}]},"target":{"nullable":true,"description":"Present when kind is assign.","allOf":[{"$ref":"#/components/schemas/InboxUserDto"}]}},"required":["kind"]},"InboxQuotedMessageDto":{"type":"object","properties":{"id":{"type":"string"},"content":{"type":"string"},"type":{"type":"string"},"direction":{"type":"string","enum":["INBOUND","OUTBOUND"]},"contactName":{"type":"string"},"contactPhone":{"type":"string"},"mediaUrl":{"type":"string"},"fileName":{"type":"string"}},"required":["id","content","type","direction"]},"CampaignAnalyticsRecipientReplyDto":{"type":"object","properties":{"type":{"type":"string","enum":["button","text"],"description":"button for a template quick reply, or text inside the 24-hour window."},"buttonId":{"type":"string","nullable":true,"description":"Button id, or null for a text reply.","example":"shop"},"text":{"type":"string","nullable":true,"description":"Reply text or button title, or null when none was stored."},"receivedAt":{"type":"string","format":"date-time","description":"When the reply was received.","example":"2026-11-01T09:00:00.000Z"},"messageId":{"type":"string","description":"Provider message id of the reply.","example":"wamid.HBgM"},"providerMessageId":{"type":"string","description":"Same value as messageId.","example":"wamid.HBgM"}},"required":["type","buttonId","text","receivedAt","messageId","providerMessageId"]},"CampaignAnalyticsErrorRecipientDto":{"type":"object","properties":{"id":{"type":"string","description":"Recipient id.","example":"cm3recipient01"},"phone":{"type":"string","nullable":true,"description":"Phone in E.164, or null when the recipient is stored by BSUID.","example":"+15551234567"},"bsuid":{"type":"string","nullable":true,"description":"Provider BSUID, or null when the recipient is stored by phone.","example":"ab.abc123xyz"},"name":{"type":"string","description":"Recipient name.","example":"Ana"},"conversationId":{"type":"string","nullable":true,"description":"Inbox conversation id, or null when none is linked.","example":"cm3dialog01"},"messageId":{"type":"string","nullable":true,"description":"Provider message id, or null when the send did not get one.","example":"wamid.HBgM"},"providerConversationId":{"type":"string","nullable":true,"description":"Provider chat id: phone digits plus @c.us, otherwise the BSUID plus @lid, or null.","example":"15551234567@c.us"},"providerMessageId":{"type":"string","nullable":true,"description":"Same value as messageId.","example":"wamid.HBgM"}},"required":["id","phone","bsuid","name","conversationId","messageId","providerConversationId","providerMessageId"]}}}}