From 83cb0b24f78a2e39695bf9f6fbabcfad11d4e7c9 Mon Sep 17 00:00:00 2001 From: KM Koushik Date: Sun, 8 Mar 2026 00:59:40 +1100 Subject: [PATCH] feat: sync sdk contact book support (#373) --- apps/docs/api-reference/openapi.json | 5236 +++++++++--------- packages/python-sdk/README.md | 3 +- packages/python-sdk/pyproject.toml | 3 +- packages/python-sdk/tests/test_resources.py | 138 + packages/python-sdk/usesend/__init__.py | 4 + packages/python-sdk/usesend/contact_books.py | 50 + packages/python-sdk/usesend/contacts.py | 50 + packages/python-sdk/usesend/types.py | 76 + packages/python-sdk/usesend/usesend.py | 3 + packages/sdk/package.json | 2 +- packages/sdk/types/schema.d.ts | 957 ++-- 11 files changed, 3577 insertions(+), 2945 deletions(-) create mode 100644 packages/python-sdk/tests/test_resources.py create mode 100644 packages/python-sdk/usesend/contact_books.py diff --git a/apps/docs/api-reference/openapi.json b/apps/docs/api-reference/openapi.json index e83b824..ce39eb1 100644 --- a/apps/docs/api-reference/openapi.json +++ b/apps/docs/api-reference/openapi.json @@ -1,2556 +1,2684 @@ { - "openapi": "3.0.0", - "info": { "version": "1.0.0", "title": "useSend API" }, - "servers": [{ "url": "https://app.usesend.com/api" }], - "components": { - "securitySchemes": { "Bearer": { "type": "http", "scheme": "bearer" } }, - "schemas": {}, - "parameters": {} - }, - "paths": { - "/v1/domains": { - "get": { - "responses": { - "200": { - "description": "Retrieve domains accessible by the API key", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "number", - "description": "The ID of the domain", - "example": 1 - }, - "name": { - "type": "string", - "description": "The name of the domain", - "example": "example.com" - }, - "teamId": { - "type": "number", - "description": "The ID of the team", - "example": 1 - }, - "status": { - "type": "string", - "enum": [ - "NOT_STARTED", - "PENDING", - "SUCCESS", - "FAILED", - "TEMPORARY_FAILURE" - ] - }, - "region": { "type": "string", "default": "us-east-1" }, - "clickTracking": { "type": "boolean", "default": false }, - "openTracking": { "type": "boolean", "default": false }, - "publicKey": { "type": "string" }, - "dkimStatus": { "type": "string", "nullable": true }, - "spfDetails": { "type": "string", "nullable": true }, - "createdAt": { "type": "string" }, - "updatedAt": { "type": "string" }, - "dmarcAdded": { "type": "boolean", "default": false }, - "isVerifying": { "type": "boolean", "default": false }, - "errorMessage": { "type": "string", "nullable": true }, - "subdomain": { "type": "string", "nullable": true }, - "verificationError": { - "type": "string", - "nullable": true - }, - "lastCheckedTime": { "type": "string", "nullable": true }, - "dnsRecords": { - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["MX", "TXT"], - "description": "DNS record type", - "example": "TXT" - }, - "name": { - "type": "string", - "description": "DNS record name", - "example": "mail" - }, - "value": { - "type": "string", - "description": "DNS record value", - "example": "v=spf1 include:amazonses.com ~all" - }, - "ttl": { - "type": "string", - "description": "DNS record TTL", - "example": "Auto" - }, - "priority": { - "type": "string", - "nullable": true, - "description": "DNS record priority", - "example": "10" - }, - "status": { - "type": "string", - "enum": [ - "NOT_STARTED", - "PENDING", - "SUCCESS", - "FAILED", - "TEMPORARY_FAILURE" - ] - }, - "recommended": { - "type": "boolean", - "description": "Whether the record is recommended" - } - }, - "required": ["type", "name", "value", "ttl", "status"] - } - } - }, - "required": [ - "id", - "name", - "teamId", - "status", - "publicKey", - "createdAt", - "updatedAt", - "dnsRecords" - ] - } - } - } - } - } - } - }, - "post": { - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "region": { "type": "string" } - }, - "required": ["name", "region"] - } - } - } - }, - "responses": { - "200": { - "description": "Create a new domain", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "id": { - "type": "number", - "description": "The ID of the domain", - "example": 1 - }, - "name": { - "type": "string", - "description": "The name of the domain", - "example": "example.com" - }, - "teamId": { - "type": "number", - "description": "The ID of the team", - "example": 1 - }, - "status": { - "type": "string", - "enum": [ - "NOT_STARTED", - "PENDING", - "SUCCESS", - "FAILED", - "TEMPORARY_FAILURE" - ] - }, - "region": { "type": "string", "default": "us-east-1" }, - "clickTracking": { "type": "boolean", "default": false }, - "openTracking": { "type": "boolean", "default": false }, - "publicKey": { "type": "string" }, - "dkimStatus": { "type": "string", "nullable": true }, - "spfDetails": { "type": "string", "nullable": true }, - "createdAt": { "type": "string" }, - "updatedAt": { "type": "string" }, - "dmarcAdded": { "type": "boolean", "default": false }, - "isVerifying": { "type": "boolean", "default": false }, - "errorMessage": { "type": "string", "nullable": true }, - "subdomain": { "type": "string", "nullable": true }, - "verificationError": { "type": "string", "nullable": true }, - "lastCheckedTime": { "type": "string", "nullable": true }, - "dnsRecords": { - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["MX", "TXT"], - "description": "DNS record type", - "example": "TXT" - }, - "name": { - "type": "string", - "description": "DNS record name", - "example": "mail" - }, - "value": { - "type": "string", - "description": "DNS record value", - "example": "v=spf1 include:amazonses.com ~all" - }, - "ttl": { - "type": "string", - "description": "DNS record TTL", - "example": "Auto" - }, - "priority": { - "type": "string", - "nullable": true, - "description": "DNS record priority", - "example": "10" - }, - "status": { - "type": "string", - "enum": [ - "NOT_STARTED", - "PENDING", - "SUCCESS", - "FAILED", - "TEMPORARY_FAILURE" - ] - }, - "recommended": { - "type": "boolean", - "description": "Whether the record is recommended" - } - }, - "required": ["type", "name", "value", "ttl", "status"] - } - } - }, - "required": [ - "id", - "name", - "teamId", - "status", - "publicKey", - "createdAt", - "updatedAt", - "dnsRecords" - ] - } - } - } - } - } - } - }, - "/v1/domains/{id}/verify": { - "put": { - "parameters": [ - { - "schema": { "type": "number", "nullable": true, "example": 1 }, - "required": false, - "name": "id", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Verify domain", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "message": { "type": "string" } }, - "required": ["message"] - } - } - } - }, - "403": { - "description": "Forbidden - API key doesn't have access to this domain", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "error": { "type": "string" } }, - "required": ["error"] - } - } - } - }, - "404": { - "description": "Domain not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "error": { "type": "string" } }, - "required": ["error"] - } - } - } - } - } - } - }, - "/v1/domains/{id}": { - "get": { - "parameters": [ - { - "schema": { "type": "number", "nullable": true, "example": 1 }, - "required": false, - "name": "id", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Retrieve the domain", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "id": { - "type": "number", - "description": "The ID of the domain", - "example": 1 - }, - "name": { - "type": "string", - "description": "The name of the domain", - "example": "example.com" - }, - "teamId": { - "type": "number", - "description": "The ID of the team", - "example": 1 - }, - "status": { - "type": "string", - "enum": [ - "NOT_STARTED", - "PENDING", - "SUCCESS", - "FAILED", - "TEMPORARY_FAILURE" - ] - }, - "region": { "type": "string", "default": "us-east-1" }, - "clickTracking": { "type": "boolean", "default": false }, - "openTracking": { "type": "boolean", "default": false }, - "publicKey": { "type": "string" }, - "dkimStatus": { "type": "string", "nullable": true }, - "spfDetails": { "type": "string", "nullable": true }, - "createdAt": { "type": "string" }, - "updatedAt": { "type": "string" }, - "dmarcAdded": { "type": "boolean", "default": false }, - "isVerifying": { "type": "boolean", "default": false }, - "errorMessage": { "type": "string", "nullable": true }, - "subdomain": { "type": "string", "nullable": true }, - "verificationError": { "type": "string", "nullable": true }, - "lastCheckedTime": { "type": "string", "nullable": true }, - "dnsRecords": { - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["MX", "TXT"], - "description": "DNS record type", - "example": "TXT" - }, - "name": { - "type": "string", - "description": "DNS record name", - "example": "mail" - }, - "value": { - "type": "string", - "description": "DNS record value", - "example": "v=spf1 include:amazonses.com ~all" - }, - "ttl": { - "type": "string", - "description": "DNS record TTL", - "example": "Auto" - }, - "priority": { - "type": "string", - "nullable": true, - "description": "DNS record priority", - "example": "10" - }, - "status": { - "type": "string", - "enum": [ - "NOT_STARTED", - "PENDING", - "SUCCESS", - "FAILED", - "TEMPORARY_FAILURE" - ] - }, - "recommended": { - "type": "boolean", - "description": "Whether the record is recommended" - } - }, - "required": ["type", "name", "value", "ttl", "status"] - } - } - }, - "required": [ - "id", - "name", - "teamId", - "status", - "publicKey", - "createdAt", - "updatedAt", - "dnsRecords" - ] - } - } - } - } - } - }, - "delete": { - "parameters": [ - { - "schema": { "type": "number", "nullable": true, "example": 1 }, - "required": false, - "name": "id", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Domain deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "id": { "type": "number" }, - "success": { "type": "boolean" }, - "message": { "type": "string" } - }, - "required": ["id", "success", "message"] - } - } - } - }, - "403": { - "description": "Forbidden - API key doesn't have access", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "error": { "type": "string" } }, - "required": ["error"] - } - } - } - }, - "404": { - "description": "Domain not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "error": { "type": "string" } }, - "required": ["error"] - } - } - } - } - } - } - }, - "/v1/emails/{emailId}": { - "get": { - "parameters": [ - { - "schema": { - "type": "string", - "minLength": 3, - "example": "cuiwqdj74rygf74" - }, - "required": true, - "name": "emailId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Retrieve the email", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "teamId": { "type": "number" }, - "to": { - "anyOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - "replyTo": { - "anyOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - "cc": { - "anyOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - "bcc": { - "anyOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - "from": { "type": "string" }, - "subject": { "type": "string" }, - "html": { "type": "string", "nullable": true }, - "text": { "type": "string", "nullable": true }, - "createdAt": { "type": "string" }, - "updatedAt": { "type": "string" }, - "emailEvents": { - "type": "array", - "items": { - "type": "object", - "properties": { - "emailId": { "type": "string" }, - "status": { - "type": "string", - "enum": [ - "SCHEDULED", - "QUEUED", - "SENT", - "DELIVERY_DELAYED", - "BOUNCED", - "REJECTED", - "RENDERING_FAILURE", - "DELIVERED", - "OPENED", - "CLICKED", - "COMPLAINED", - "FAILED", - "CANCELLED", - "SUPPRESSED" - ] - }, - "createdAt": { "type": "string" }, - "data": { "nullable": true } - }, - "required": ["emailId", "status", "createdAt"] - } - } - }, - "required": [ - "id", - "teamId", - "to", - "from", - "subject", - "html", - "text", - "createdAt", - "updatedAt", - "emailEvents" - ] - } - } - } - } - } - }, - "patch": { - "parameters": [ - { - "schema": { - "type": "string", - "minLength": 3, - "example": "cuiwqdj74rygf74" - }, - "required": true, - "name": "emailId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "scheduledAt": { "type": "string", "format": "date-time" } - }, - "required": ["scheduledAt"] - } - } - } - }, - "responses": { - "200": { - "description": "Retrieve the user", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "emailId": { "type": "string" } } - } - } - } - } - } - } - }, - "/v1/emails": { - "get": { - "parameters": [ - { - "schema": { "type": "string", "default": "1", "example": "1" }, - "required": false, - "name": "page", - "in": "query" - }, - { - "schema": { "type": "string", "default": "50", "example": "50" }, - "required": false, - "name": "limit", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "date-time", - "example": "2024-01-01T00:00:00Z" - }, - "required": false, - "name": "startDate", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "date-time", - "example": "2024-01-31T23:59:59Z" - }, - "required": false, - "name": "endDate", - "in": "query" - }, - { - "schema": { - "anyOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ], - "example": "123" - }, - "required": false, - "name": "domainId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Retrieve a list of emails", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "to": { - "anyOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - "replyTo": { - "anyOf": [ - { "type": "string" }, - { - "type": "array", - "items": { "type": "string" } - }, - { "nullable": true } - ] - }, - "cc": { - "anyOf": [ - { "type": "string" }, - { - "type": "array", - "items": { "type": "string" } - }, - { "nullable": true } - ] - }, - "bcc": { - "anyOf": [ - { "type": "string" }, - { - "type": "array", - "items": { "type": "string" } - }, - { "nullable": true } - ] - }, - "from": { "type": "string" }, - "subject": { "type": "string" }, - "html": { "type": "string", "nullable": true }, - "text": { "type": "string", "nullable": true }, - "createdAt": { "type": "string" }, - "updatedAt": { "type": "string" }, - "latestStatus": { - "type": "string", - "nullable": true, - "enum": [ - "SCHEDULED", - "QUEUED", - "SENT", - "DELIVERY_DELAYED", - "BOUNCED", - "REJECTED", - "RENDERING_FAILURE", - "DELIVERED", - "OPENED", - "CLICKED", - "COMPLAINED", - "FAILED", - "CANCELLED", - "SUPPRESSED" - ] - }, - "scheduledAt": { - "type": "string", - "nullable": true, - "format": "date-time" - }, - "domainId": { "type": "number", "nullable": true } - }, - "required": [ - "id", - "to", - "from", - "subject", - "html", - "text", - "createdAt", - "updatedAt", - "latestStatus", - "scheduledAt", - "domainId" - ] - } - }, - "count": { "type": "number" } - }, - "required": ["data", "count"] - } - } - } - } - } - }, - "post": { - "parameters": [ - { - "schema": { - "type": "string", - "minLength": 1, - "maxLength": 256, - "description": "Pass the optional Idempotency-Key header to make the request safe to retry. The key can be up to 256 characters. The server stores the canonical request body and behaves as follows:\n\n- Same key + same request body → returns the original emailId with 200 OK without re-sending.\n- Same key + different request body → returns 409 Conflict with code: NOT_UNIQUE so you can detect the mismatch.\n- Same key while another request is still being processed → returns 409 Conflict; retry after a short delay or once the first request completes.\n\nEntries expire after 24 hours. Use a unique key per logical send (for example, an order or signup ID)." - }, - "required": false, - "name": "Idempotency-Key", - "in": "header" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "to": { - "anyOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - "from": { "type": "string" }, - "subject": { - "type": "string", - "minLength": 1, - "description": "Optional when templateId is provided" - }, - "templateId": { - "type": "string", - "description": "ID of a template from the dashboard" - }, - "variables": { - "type": "object", - "additionalProperties": { "type": "string" } - }, - "replyTo": { - "anyOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - "cc": { - "anyOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - "bcc": { - "anyOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - "text": { - "type": "string", - "nullable": true, - "minLength": 1 - }, - "html": { - "type": "string", - "nullable": true, - "minLength": 1 - }, - "headers": { - "type": "object", - "additionalProperties": { - "type": "string", - "minLength": 1 - }, - "description": "Custom headers to included with the emails" - }, - "attachments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "filename": { "type": "string", "minLength": 1 }, - "content": { "type": "string", "minLength": 1 } - }, - "required": ["filename", "content"] - }, - "maxItems": 10 - }, - "scheduledAt": { "type": "string", "format": "date-time" }, - "inReplyToId": { "type": "string", "nullable": true } - }, - "required": ["to", "from"] - } - } - } - }, - "responses": { - "200": { - "description": "Retrieve the user", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "emailId": { "type": "string" } } - } - } - } - } - } - } - }, - "/v1/emails/batch": { - "post": { - "parameters": [ - { - "schema": { - "type": "string", - "minLength": 1, - "maxLength": 256, - "description": "Pass the optional Idempotency-Key header to make the request safe to retry. The key can be up to 256 characters. The server stores the canonical request body and behaves as follows:\n\n- Same key + same request body → returns the original emailId with 200 OK without re-sending.\n- Same key + different request body → returns 409 Conflict with code: NOT_UNIQUE so you can detect the mismatch.\n- Same key while another request is still being processed → returns 409 Conflict; retry after a short delay or once the first request completes.\n\nEntries expire after 24 hours. Use a unique key per logical send (for example, an order or signup ID)." - }, - "required": false, - "name": "Idempotency-Key", - "in": "header" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "object", - "properties": { - "to": { - "anyOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - "from": { "type": "string" }, - "subject": { - "type": "string", - "minLength": 1, - "description": "Optional when templateId is provided" - }, - "templateId": { - "type": "string", - "description": "ID of a template from the dashboard" - }, - "variables": { - "type": "object", - "additionalProperties": { "type": "string" } - }, - "replyTo": { - "anyOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - "cc": { - "anyOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - "bcc": { - "anyOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - "text": { - "type": "string", - "nullable": true, - "minLength": 1 - }, - "html": { - "type": "string", - "nullable": true, - "minLength": 1 - }, - "headers": { - "type": "object", - "additionalProperties": { - "type": "string", - "minLength": 1 - }, - "description": "Custom headers to included with the emails" - }, - "attachments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "filename": { "type": "string", "minLength": 1 }, - "content": { "type": "string", "minLength": 1 } - }, - "required": ["filename", "content"] - }, - "maxItems": 10 - }, - "scheduledAt": { "type": "string", "format": "date-time" }, - "inReplyToId": { "type": "string", "nullable": true } - }, - "required": ["to", "from"] - }, - "maxItems": 100 - } - } - } - }, - "responses": { - "200": { - "description": "List of successfully created email IDs", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "type": "object", - "properties": { "emailId": { "type": "string" } }, - "required": ["emailId"] - } - } - }, - "required": ["data"] - } - } - } - } - } - } - }, - "/v1/emails/{emailId}/cancel": { - "post": { - "parameters": [ - { - "schema": { - "type": "string", - "minLength": 3, - "example": "cuiwqdj74rygf74" - }, - "required": true, - "name": "emailId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Retrieve the user", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "emailId": { "type": "string" } } - } - } - } - } - } - } - }, - "/v1/contactBooks": { - "get": { - "responses": { - "200": { - "description": "Retrieve contact books accessible by the API key", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "The ID of the contact book", - "example": "clx1234567890" - }, - "name": { - "type": "string", - "description": "The name of the contact book", - "example": "Newsletter Subscribers" - }, - "teamId": { - "type": "number", - "description": "The ID of the team", - "example": 1 - }, - "properties": { - "type": "object", - "additionalProperties": { "type": "string" }, - "description": "Custom properties for the contact book", - "example": { "customField1": "value1" } - }, - "emoji": { - "type": "string", - "description": "The emoji associated with the contact book", - "example": "📙" - }, - "doubleOptInEnabled": { - "type": "boolean", - "description": "Whether double opt-in is enabled for new contacts", - "example": true - }, - "doubleOptInFrom": { - "type": "string", - "nullable": true, - "description": "From address used for double opt-in emails (must use a verified domain)", - "example": "Newsletter " - }, - "doubleOptInSubject": { - "type": "string", - "nullable": true, - "description": "Subject line used for double opt-in confirmation email", - "example": "Please confirm your subscription" - }, - "doubleOptInContent": { - "type": "string", - "nullable": true, - "description": "Email editor JSON content used for double opt-in confirmation" - }, - "createdAt": { - "type": "string", - "description": "The creation timestamp" - }, - "updatedAt": { - "type": "string", - "description": "The last update timestamp" - }, - "_count": { - "type": "object", - "properties": { - "contacts": { - "type": "number", - "description": "The number of contacts in the contact book" - } - } - } - }, - "required": [ - "id", - "name", - "teamId", - "properties", - "emoji", - "createdAt", - "updatedAt" - ] - } - } - } - } - } - } - }, - "post": { - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { "type": "string", "minLength": 1 }, - "emoji": { "type": "string" }, - "properties": { - "type": "object", - "additionalProperties": { "type": "string" } - }, - "doubleOptInEnabled": { - "type": "boolean", - "description": "Whether double opt-in is enabled for new contacts" - }, - "doubleOptInFrom": { - "type": "string", - "nullable": true, - "description": "From address used for double opt-in emails (must use a verified domain)" - }, - "doubleOptInSubject": { - "type": "string", - "description": "Subject line used for double opt-in confirmation email" - }, - "doubleOptInContent": { - "type": "string", - "description": "Email editor JSON content used for double opt-in confirmation" - } - }, - "required": ["name"] - } - } - } - }, - "responses": { - "200": { - "description": "Create a new contact book", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "teamId": { "type": "number" }, - "properties": { - "type": "object", - "additionalProperties": { "type": "string" } - }, - "emoji": { "type": "string" }, - "doubleOptInEnabled": { "type": "boolean", "description": "Whether double opt-in is enabled for new contacts" }, - "doubleOptInFrom": { "type": "string", "nullable": true, "description": "From address used for double opt-in emails" }, - "doubleOptInSubject": { "type": "string", "nullable": true, "description": "Subject line used for double opt-in confirmation email" }, - "doubleOptInContent": { "type": "string", "nullable": true, "description": "Email editor JSON content used for double opt-in confirmation" }, - "createdAt": { "type": "string" }, - "updatedAt": { "type": "string" } - }, - "required": [ - "id", - "name", - "teamId", - "properties", - "emoji", - "createdAt", - "updatedAt" - ] - } - } - } - } - } - } - }, - "/v1/contactBooks/{contactBookId}": { - "get": { - "parameters": [ - { - "schema": { "type": "string", "example": "clx1234567890" }, - "required": true, - "name": "contactBookId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Retrieve the contact book", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "teamId": { "type": "number" }, - "properties": { - "type": "object", - "additionalProperties": { "type": "string" } - }, - "emoji": { "type": "string" }, - "doubleOptInEnabled": { "type": "boolean", "description": "Whether double opt-in is enabled for new contacts" }, - "doubleOptInFrom": { "type": "string", "nullable": true, "description": "From address used for double opt-in emails" }, - "doubleOptInSubject": { "type": "string", "nullable": true, "description": "Subject line used for double opt-in confirmation email" }, - "doubleOptInContent": { "type": "string", "nullable": true, "description": "Email editor JSON content used for double opt-in confirmation" }, - "createdAt": { "type": "string" }, - "updatedAt": { "type": "string" }, - "_count": { - "type": "object", - "properties": { - "contacts": { "type": "number" } - } - } - }, - "required": [ - "id", - "name", - "teamId", - "properties", - "emoji", - "createdAt", - "updatedAt" - ] - } - } - } - }, - "403": { - "description": "Forbidden - API key doesn't have access", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "error": { "type": "string" } }, - "required": ["error"] - } - } - } - }, - "404": { - "description": "Contact book not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "error": { "type": "string" } }, - "required": ["error"] - } - } - } - } - } - }, - "patch": { - "parameters": [ - { - "schema": { "type": "string", "example": "clx1234567890" }, - "required": true, - "name": "contactBookId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { "type": "string", "minLength": 1 }, - "emoji": { "type": "string" }, - "properties": { - "type": "object", - "additionalProperties": { "type": "string" } - }, - "doubleOptInEnabled": { - "type": "boolean", - "description": "Whether double opt-in is enabled for new contacts" - }, - "doubleOptInFrom": { - "type": "string", - "nullable": true, - "description": "From address used for double opt-in emails (must use a verified domain)" - }, - "doubleOptInSubject": { - "type": "string", - "description": "Subject line used for double opt-in confirmation email" - }, - "doubleOptInContent": { - "type": "string", - "description": "Email editor JSON content used for double opt-in confirmation" - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Update the contact book", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "teamId": { "type": "number" }, - "properties": { - "type": "object", - "additionalProperties": { "type": "string" } - }, - "emoji": { "type": "string" }, - "doubleOptInEnabled": { "type": "boolean", "description": "Whether double opt-in is enabled for new contacts" }, - "doubleOptInFrom": { "type": "string", "nullable": true, "description": "From address used for double opt-in emails" }, - "doubleOptInSubject": { "type": "string", "nullable": true, "description": "Subject line used for double opt-in confirmation email" }, - "doubleOptInContent": { "type": "string", "nullable": true, "description": "Email editor JSON content used for double opt-in confirmation" }, - "createdAt": { "type": "string" }, - "updatedAt": { "type": "string" } - }, - "required": [ - "id", - "name", - "teamId", - "properties", - "emoji", - "createdAt", - "updatedAt" - ] - } - } - } - }, - "403": { - "description": "Forbidden - API key doesn't have access", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "error": { "type": "string" } }, - "required": ["error"] - } - } - } - }, - "404": { - "description": "Contact book not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "error": { "type": "string" } }, - "required": ["error"] - } - } - } - } - } - }, - "delete": { - "parameters": [ - { - "schema": { "type": "string", "example": "clx1234567890" }, - "required": true, - "name": "contactBookId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Contact book deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "success": { "type": "boolean" }, - "message": { "type": "string" } - }, - "required": ["id", "success", "message"] - } - } - } - }, - "403": { - "description": "Forbidden - API key doesn't have access", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "error": { "type": "string" } }, - "required": ["error"] - } - } - } - }, - "404": { - "description": "Contact book not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "error": { "type": "string" } }, - "required": ["error"] - } - } - } - } - } - } - }, - "/v1/contactBooks/{contactBookId}/contacts": { - "post": { - "parameters": [ - { - "schema": { - "type": "string", - "minLength": 3, - "example": "cuiwqdj74rygf74" - }, - "required": true, - "name": "contactBookId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "email": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "properties": { - "type": "object", - "additionalProperties": { "type": "string" } - }, - "subscribed": { "type": "boolean" } - }, - "required": ["email"] - } - } - } - }, - "responses": { - "200": { - "description": "Retrieve the user", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "contactId": { "type": "string" } } - } - } - } - } - } - }, - "get": { - "parameters": [ - { - "schema": { "type": "string", "example": "cuiwqdj74rygf74" }, - "required": true, - "name": "contactBookId", - "in": "path" - }, - { - "schema": { "type": "string" }, - "required": false, - "name": "emails", - "in": "query" - }, - { - "schema": { "type": "number" }, - "required": false, - "name": "page", - "in": "query" - }, - { - "schema": { "type": "number" }, - "required": false, - "name": "limit", - "in": "query" - }, - { - "schema": { "type": "string" }, - "required": false, - "name": "ids", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Retrieve multiple contacts", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string", "nullable": true }, - "lastName": { "type": "string", "nullable": true }, - "email": { "type": "string" }, - "subscribed": { "type": "boolean", "default": true }, - "properties": { - "type": "object", - "additionalProperties": { "type": "string" } - }, - "contactBookId": { "type": "string" }, - "createdAt": { "type": "string" }, - "updatedAt": { "type": "string" } - }, - "required": [ - "id", - "email", - "properties", - "contactBookId", - "createdAt", - "updatedAt" - ] - } - } - } - } - } - } - } - }, - "/v1/contactBooks/{contactBookId}/contacts/bulk": { - "delete": { - "parameters": [ - { - "schema": { - "type": "string", - "minLength": 3, - "example": "cuiwqdj74rygf74" - }, - "required": true, - "name": "contactBookId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "contactIds": { - "type": "array", - "items": { "type": "string" }, - "minItems": 1, - "maxItems": 1000 - } - }, - "required": ["contactIds"] - } - } - } - }, - "responses": { - "200": { - "description": "Bulk delete contacts from a contact book", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean" }, - "count": { "type": "number" } - }, - "required": ["success", "count"] - } - } - } - }, - "403": { - "description": "Forbidden - API key doesn't have access", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "error": { "type": "string" } }, - "required": ["error"] - } - } - } - }, - "404": { - "description": "Contact book not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "error": { "type": "string" } }, - "required": ["error"] - } - } - } - } - } - }, - "post": { - "parameters": [ - { - "schema": { - "type": "string", - "minLength": 3, - "example": "cuiwqdj74rygf74" - }, - "required": true, - "name": "contactBookId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "object", - "properties": { - "email": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "properties": { - "type": "object", - "additionalProperties": { "type": "string" } - }, - "subscribed": { "type": "boolean" } - }, - "required": ["email"] - }, - "minItems": 1, - "maxItems": 1000 - } - } - } - }, - "responses": { - "200": { - "description": "Bulk add contacts to a contact book", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { "type": "string" }, - "count": { "type": "number" } - }, - "required": ["message", "count"] - } - } - } - }, - "403": { - "description": "Forbidden - API key doesn't have access", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "error": { "type": "string" } }, - "required": ["error"] - } - } - } - }, - "404": { - "description": "Contact book not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "error": { "type": "string" } }, - "required": ["error"] - } - } - } - } - } - } - }, - "/v1/contactBooks/{contactBookId}/contacts/{contactId}": { - "patch": { - "parameters": [ - { - "schema": { "type": "string", "example": "cuiwqdj74rygf74" }, - "required": true, - "name": "contactBookId", - "in": "path" - }, - { - "schema": { "type": "string", "example": "cuiwqdj74rygf74" }, - "required": true, - "name": "contactId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "properties": { - "type": "object", - "additionalProperties": { "type": "string" } - }, - "subscribed": { "type": "boolean" } - } - } - } - } - }, - "responses": { - "200": { - "description": "Retrieve the user", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "contactId": { "type": "string" } } - } - } - } - } - } - }, - "get": { - "parameters": [ - { - "schema": { "type": "string", "example": "cuiwqdj74rygf74" }, - "required": true, - "name": "contactBookId", - "in": "path" - }, - { - "schema": { "type": "string", "example": "cuiwqdj74rygf74" }, - "required": true, - "name": "contactId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Retrieve the contact", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string", "nullable": true }, - "lastName": { "type": "string", "nullable": true }, - "email": { "type": "string" }, - "subscribed": { "type": "boolean", "default": true }, - "properties": { - "type": "object", - "additionalProperties": { "type": "string" } - }, - "contactBookId": { "type": "string" }, - "createdAt": { "type": "string" }, - "updatedAt": { "type": "string" } - }, - "required": [ - "id", - "email", - "properties", - "contactBookId", - "createdAt", - "updatedAt" - ] - } - } - } - } - } - }, - "put": { - "parameters": [ - { - "schema": { - "type": "string", - "minLength": 3, - "example": "cuiwqdj74rygf74" - }, - "required": true, - "name": "contactBookId", - "in": "path" - }, - { - "schema": { - "type": "string", - "minLength": 3, - "example": "cuiwqdj74rygf74" - }, - "required": true, - "name": "contactId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "email": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "properties": { - "type": "object", - "additionalProperties": { "type": "string" } - }, - "subscribed": { "type": "boolean" } - }, - "required": ["email"] - } - } - } - }, - "responses": { - "200": { - "description": "Contact upserted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "contactId": { "type": "string" } }, - "required": ["contactId"] - } - } - } - } - } - }, - "delete": { - "parameters": [ - { - "schema": { "type": "string", "example": "cuiwqdj74rygf74" }, - "required": true, - "name": "contactBookId", - "in": "path" - }, - { - "schema": { "type": "string", "example": "cuiwqdj74rygf74" }, - "required": true, - "name": "contactId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Contact deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "success": { "type": "boolean" } }, - "required": ["success"] - } - } - } - } - } - } - }, - "/v1/campaigns": { - "get": { - "parameters": [ - { - "schema": { "type": "string", "default": "1", "example": "1" }, - "required": false, - "name": "page", - "in": "query", - "description": "Page number for pagination (default: 1)" - }, - { - "schema": { - "type": "string", - "enum": [ - "DRAFT", - "SCHEDULED", - "RUNNING", - "PAUSED", - "SENT" - ], - "example": "DRAFT" - }, - "required": false, - "name": "status", - "in": "query", - "description": "Filter campaigns by status" - }, - { - "schema": { "type": "string", "example": "newsletter" }, - "required": false, - "name": "search", - "in": "query", - "description": "Search campaigns by name or subject" - } - ], - "responses": { - "200": { - "description": "Get list of campaigns", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "campaigns": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "from": { "type": "string" }, - "subject": { "type": "string" }, - "createdAt": { "type": "string", "format": "date-time" }, - "updatedAt": { "type": "string", "format": "date-time" }, - "status": { "type": "string", "enum": ["DRAFT", "SCHEDULED", "RUNNING", "PAUSED", "SENT"] }, - "scheduledAt": { "type": "string", "nullable": true, "format": "date-time" }, - "total": { "type": "integer" }, - "sent": { "type": "integer" }, - "delivered": { "type": "integer" }, - "unsubscribed": { "type": "integer" } - }, - "required": [ - "id", - "name", - "from", - "subject", - "createdAt", - "updatedAt", - "status", - "scheduledAt", - "total", - "sent", - "delivered", - "unsubscribed" - ] - } - }, - "totalPage": { "type": "integer" } - }, - "required": ["campaigns", "totalPage"] - } - } - } - } - } - }, - "post": { - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { "type": "string", "minLength": 1 }, - "from": { "type": "string", "minLength": 1 }, - "subject": { "type": "string", "minLength": 1 }, - "previewText": { "type": "string" }, - "contactBookId": { "type": "string", "minLength": 1 }, - "content": { "type": "string", "minLength": 1 }, - "html": { "type": "string", "minLength": 1 }, - "replyTo": { - "anyOf": [ - { "type": "string", "minLength": 1 }, - { - "type": "array", - "items": { "type": "string", "minLength": 1 } - } - ] - }, - "cc": { - "anyOf": [ - { "type": "string", "minLength": 1 }, - { - "type": "array", - "items": { "type": "string", "minLength": 1 } - } - ] - }, - "bcc": { - "anyOf": [ - { "type": "string", "minLength": 1 }, - { - "type": "array", - "items": { "type": "string", "minLength": 1 } - } - ] - }, - "sendNow": { "type": "boolean" }, - "scheduledAt": { - "type": "string", - "description": "Timestamp in ISO 8601 format or natural language (e.g., 'tomorrow 9am', 'next monday 10:30')" - }, - "batchSize": { - "type": "integer", - "minimum": 1, - "maximum": 100000 - } - }, - "required": ["name", "from", "subject", "contactBookId"] - } - } - } - }, - "responses": { - "200": { - "description": "Create a campaign", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "from": { "type": "string" }, - "subject": { "type": "string" }, - "previewText": { "type": "string", "nullable": true }, - "contactBookId": { "type": "string", "nullable": true }, - "html": { "type": "string", "nullable": true }, - "content": { "type": "string", "nullable": true }, - "status": { "type": "string", "enum": ["DRAFT", "SCHEDULED", "RUNNING", "PAUSED", "SENT"] }, - "scheduledAt": { - "type": "string", - "nullable": true, - "format": "date-time" - }, - "batchSize": { "type": "integer" }, - "batchWindowMinutes": { "type": "integer" }, - "total": { "type": "integer" }, - "sent": { "type": "integer" }, - "delivered": { "type": "integer" }, - "opened": { "type": "integer" }, - "clicked": { "type": "integer" }, - "unsubscribed": { "type": "integer" }, - "bounced": { "type": "integer" }, - "hardBounced": { "type": "integer" }, - "complained": { "type": "integer" }, - "replyTo": { - "type": "array", - "items": { "type": "string" } - }, - "cc": { "type": "array", "items": { "type": "string" } }, - "bcc": { "type": "array", "items": { "type": "string" } }, - "createdAt": { "type": "string", "format": "date-time" }, - "updatedAt": { "type": "string", "format": "date-time" } - }, - "required": [ - "id", - "name", - "from", - "subject", - "previewText", - "contactBookId", - "html", - "content", - "status", - "scheduledAt", - "batchSize", - "batchWindowMinutes", - "total", - "sent", - "delivered", - "opened", - "clicked", - "unsubscribed", - "bounced", - "hardBounced", - "complained", - "replyTo", - "cc", - "bcc", - "createdAt", - "updatedAt" - ] - } - } - } - } - } - } - }, - "/v1/campaigns/{campaignId}": { - "parameters": [ - { - "schema": { - "type": "string", - "minLength": 1, - "example": "cmp_123" - }, - "required": true, - "name": "campaignId", - "in": "path" - } - ], - "get": { - "responses": { - "200": { - "description": "Get campaign details", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "from": { "type": "string" }, - "subject": { "type": "string" }, - "previewText": { "type": "string", "nullable": true }, - "contactBookId": { "type": "string", "nullable": true }, - "html": { "type": "string", "nullable": true }, - "content": { "type": "string", "nullable": true }, - "status": { "type": "string", "enum": ["DRAFT", "SCHEDULED", "RUNNING", "PAUSED", "SENT"] }, - "scheduledAt": { - "type": "string", - "nullable": true, - "format": "date-time" - }, - "batchSize": { "type": "integer" }, - "batchWindowMinutes": { "type": "integer" }, - "total": { "type": "integer" }, - "sent": { "type": "integer" }, - "delivered": { "type": "integer" }, - "opened": { "type": "integer" }, - "clicked": { "type": "integer" }, - "unsubscribed": { "type": "integer" }, - "bounced": { "type": "integer" }, - "hardBounced": { "type": "integer" }, - "complained": { "type": "integer" }, - "replyTo": { - "type": "array", - "items": { "type": "string" } - }, - "cc": { "type": "array", "items": { "type": "string" } }, - "bcc": { "type": "array", "items": { "type": "string" } }, - "createdAt": { "type": "string", "format": "date-time" }, - "updatedAt": { "type": "string", "format": "date-time" } - }, - "required": [ - "id", - "name", - "from", - "subject", - "previewText", - "contactBookId", - "html", - "content", - "status", - "scheduledAt", - "batchSize", - "batchWindowMinutes", - "total", - "sent", - "delivered", - "opened", - "clicked", - "unsubscribed", - "bounced", - "hardBounced", - "complained", - "replyTo", - "cc", - "bcc", - "createdAt", - "updatedAt" - ] - } - } - } - } - } - }, - "delete": { - "responses": { - "200": { - "description": "Delete campaign", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "from": { "type": "string" }, - "subject": { "type": "string" }, - "previewText": { "type": "string", "nullable": true }, - "contactBookId": { "type": "string", "nullable": true }, - "html": { "type": "string", "nullable": true }, - "content": { "type": "string", "nullable": true }, - "status": { "type": "string", "enum": ["DRAFT", "SCHEDULED", "RUNNING", "PAUSED", "SENT"] }, - "scheduledAt": { - "type": "string", - "nullable": true, - "format": "date-time" - }, - "batchSize": { "type": "integer" }, - "batchWindowMinutes": { "type": "integer" }, - "total": { "type": "integer" }, - "sent": { "type": "integer" }, - "delivered": { "type": "integer" }, - "opened": { "type": "integer" }, - "clicked": { "type": "integer" }, - "unsubscribed": { "type": "integer" }, - "bounced": { "type": "integer" }, - "hardBounced": { "type": "integer" }, - "complained": { "type": "integer" }, - "replyTo": { - "type": "array", - "items": { "type": "string" } - }, - "cc": { "type": "array", "items": { "type": "string" } }, - "bcc": { "type": "array", "items": { "type": "string" } }, - "createdAt": { "type": "string", "format": "date-time" }, - "updatedAt": { "type": "string", "format": "date-time" } - }, - "required": [ - "id", - "name", - "from", - "subject", - "previewText", - "contactBookId", - "html", - "content", - "status", - "scheduledAt", - "batchSize", - "batchWindowMinutes", - "total", - "sent", - "delivered", - "opened", - "clicked", - "unsubscribed", - "bounced", - "hardBounced", - "complained", - "replyTo", - "cc", - "bcc", - "createdAt", - "updatedAt" - ] - } - } - } - } - } - } - }, - "/v1/campaigns/{campaignId}/schedule": { - "post": { - "parameters": [ - { - "schema": { - "type": "string", - "minLength": 1, - "example": "cmp_123" - }, - "required": true, - "name": "campaignId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "scheduledAt": { - "type": "string", - "description": "Timestamp in ISO 8601 format or natural language (e.g., 'tomorrow 9am', 'next monday 10:30')" - }, - "batchSize": { - "type": "integer", - "minimum": 1, - "maximum": 100000 - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Schedule a campaign", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "success": { "type": "boolean" } }, - "required": ["success"] - } - } - } - } - } - } - }, - "/v1/campaigns/{campaignId}/pause": { - "post": { - "parameters": [ - { - "schema": { - "type": "string", - "minLength": 1, - "example": "cmp_123" - }, - "required": true, - "name": "campaignId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Pause a campaign", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "success": { "type": "boolean" } }, - "required": ["success"] - } - } - } - } - } - } - }, - "/v1/campaigns/{campaignId}/resume": { - "post": { - "parameters": [ - { - "schema": { - "type": "string", - "minLength": 1, - "example": "cmp_123" - }, - "required": true, - "name": "campaignId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Resume a campaign", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "success": { "type": "boolean" } }, - "required": ["success"] - } - } - } - } - } - } - }, - "/v1/analytics/email-time-series": { - "get": { - "parameters": [ - { - "schema": { - "type": "string", - "enum": ["7", "30"], - "example": "30" - }, - "required": false, - "name": "days", - "in": "query", - "description": "Number of days to retrieve data for (default: 30)" - }, - { - "schema": { "type": "string" }, - "required": false, - "name": "domainId", - "in": "query", - "description": "Filter by domain ID" - } - ], - "responses": { - "200": { - "description": "Retrieve email time series data", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "result": { - "type": "array", - "items": { - "type": "object", - "properties": { - "date": { "type": "string" }, - "sent": { "type": "integer" }, - "delivered": { "type": "integer" }, - "opened": { "type": "integer" }, - "clicked": { "type": "integer" }, - "bounced": { "type": "integer" }, - "complained": { "type": "integer" } - }, - "required": [ - "date", - "sent", - "delivered", - "opened", - "clicked", - "bounced", - "complained" - ] - } - }, - "totalCounts": { - "type": "object", - "properties": { - "sent": { "type": "integer" }, - "delivered": { "type": "integer" }, - "opened": { "type": "integer" }, - "clicked": { "type": "integer" }, - "bounced": { "type": "integer" }, - "complained": { "type": "integer" } - }, - "required": [ - "sent", - "delivered", - "opened", - "clicked", - "bounced", - "complained" - ] - } - }, - "required": ["result", "totalCounts"] - } - } - } - } - } - } - }, - "/v1/analytics/reputation-metrics": { - "get": { - "parameters": [ - { - "schema": { "type": "string" }, - "required": false, - "name": "domainId", - "in": "query", - "description": "Filter by domain ID" - } - ], - "responses": { - "200": { - "description": "Retrieve reputation metrics data", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "delivered": { "type": "integer" }, - "hardBounced": { "type": "integer" }, - "complained": { "type": "integer" }, - "bounceRate": { "type": "number" }, - "complaintRate": { "type": "number" } - }, - "required": [ - "delivered", - "hardBounced", - "complained", - "bounceRate", - "complaintRate" - ] - } - } - } - } - } - } - } - } + "openapi": "3.0.0", + "info": { "version": "1.0.0", "title": "useSend API" }, + "servers": [{ "url": "https://app.usesend.com/api" }], + "components": { + "securitySchemes": { "Bearer": { "type": "http", "scheme": "bearer" } }, + "schemas": {}, + "parameters": {} + }, + "paths": { + "/v1/domains": { + "get": { + "responses": { + "200": { + "description": "Retrieve domains accessible by the API key", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "number", + "description": "The ID of the domain", + "example": 1 + }, + "name": { + "type": "string", + "description": "The name of the domain", + "example": "example.com" + }, + "teamId": { + "type": "number", + "description": "The ID of the team", + "example": 1 + }, + "status": { + "type": "string", + "enum": [ + "NOT_STARTED", + "PENDING", + "SUCCESS", + "FAILED", + "TEMPORARY_FAILURE" + ] + }, + "region": { "type": "string", "default": "us-east-1" }, + "clickTracking": { "type": "boolean", "default": false }, + "openTracking": { "type": "boolean", "default": false }, + "publicKey": { "type": "string" }, + "dkimStatus": { "type": "string", "nullable": true }, + "spfDetails": { "type": "string", "nullable": true }, + "createdAt": { "type": "string" }, + "updatedAt": { "type": "string" }, + "dmarcAdded": { "type": "boolean", "default": false }, + "isVerifying": { "type": "boolean", "default": false }, + "errorMessage": { "type": "string", "nullable": true }, + "subdomain": { "type": "string", "nullable": true }, + "verificationError": { + "type": "string", + "nullable": true + }, + "lastCheckedTime": { "type": "string", "nullable": true }, + "dnsRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["MX", "TXT"], + "description": "DNS record type", + "example": "TXT" + }, + "name": { + "type": "string", + "description": "DNS record name", + "example": "mail" + }, + "value": { + "type": "string", + "description": "DNS record value", + "example": "v=spf1 include:amazonses.com ~all" + }, + "ttl": { + "type": "string", + "description": "DNS record TTL", + "example": "Auto" + }, + "priority": { + "type": "string", + "nullable": true, + "description": "DNS record priority", + "example": "10" + }, + "status": { + "type": "string", + "enum": [ + "NOT_STARTED", + "PENDING", + "SUCCESS", + "FAILED", + "TEMPORARY_FAILURE" + ] + }, + "recommended": { + "type": "boolean", + "description": "Whether the record is recommended" + } + }, + "required": ["type", "name", "value", "ttl", "status"] + } + } + }, + "required": [ + "id", + "name", + "teamId", + "status", + "publicKey", + "createdAt", + "updatedAt", + "dnsRecords" + ] + } + } + } + } + } + } + }, + "post": { + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "region": { "type": "string" } + }, + "required": ["name", "region"] + } + } + } + }, + "responses": { + "200": { + "description": "Create a new domain", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number", + "description": "The ID of the domain", + "example": 1 + }, + "name": { + "type": "string", + "description": "The name of the domain", + "example": "example.com" + }, + "teamId": { + "type": "number", + "description": "The ID of the team", + "example": 1 + }, + "status": { + "type": "string", + "enum": [ + "NOT_STARTED", + "PENDING", + "SUCCESS", + "FAILED", + "TEMPORARY_FAILURE" + ] + }, + "region": { "type": "string", "default": "us-east-1" }, + "clickTracking": { "type": "boolean", "default": false }, + "openTracking": { "type": "boolean", "default": false }, + "publicKey": { "type": "string" }, + "dkimStatus": { "type": "string", "nullable": true }, + "spfDetails": { "type": "string", "nullable": true }, + "createdAt": { "type": "string" }, + "updatedAt": { "type": "string" }, + "dmarcAdded": { "type": "boolean", "default": false }, + "isVerifying": { "type": "boolean", "default": false }, + "errorMessage": { "type": "string", "nullable": true }, + "subdomain": { "type": "string", "nullable": true }, + "verificationError": { "type": "string", "nullable": true }, + "lastCheckedTime": { "type": "string", "nullable": true }, + "dnsRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["MX", "TXT"], + "description": "DNS record type", + "example": "TXT" + }, + "name": { + "type": "string", + "description": "DNS record name", + "example": "mail" + }, + "value": { + "type": "string", + "description": "DNS record value", + "example": "v=spf1 include:amazonses.com ~all" + }, + "ttl": { + "type": "string", + "description": "DNS record TTL", + "example": "Auto" + }, + "priority": { + "type": "string", + "nullable": true, + "description": "DNS record priority", + "example": "10" + }, + "status": { + "type": "string", + "enum": [ + "NOT_STARTED", + "PENDING", + "SUCCESS", + "FAILED", + "TEMPORARY_FAILURE" + ] + }, + "recommended": { + "type": "boolean", + "description": "Whether the record is recommended" + } + }, + "required": ["type", "name", "value", "ttl", "status"] + } + } + }, + "required": [ + "id", + "name", + "teamId", + "status", + "publicKey", + "createdAt", + "updatedAt", + "dnsRecords" + ] + } + } + } + } + } + } + }, + "/v1/domains/{id}/verify": { + "put": { + "parameters": [ + { + "schema": { "type": "number", "nullable": true, "example": 1 }, + "required": false, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Verify domain", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } }, + "required": ["message"] + } + } + } + }, + "403": { + "description": "Forbidden - API key doesn't have access to this domain", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "error": { "type": "string" } }, + "required": ["error"] + } + } + } + }, + "404": { + "description": "Domain not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "error": { "type": "string" } }, + "required": ["error"] + } + } + } + } + } + } + }, + "/v1/domains/{id}": { + "get": { + "parameters": [ + { + "schema": { "type": "number", "nullable": true, "example": 1 }, + "required": false, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Retrieve the domain", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "number", + "description": "The ID of the domain", + "example": 1 + }, + "name": { + "type": "string", + "description": "The name of the domain", + "example": "example.com" + }, + "teamId": { + "type": "number", + "description": "The ID of the team", + "example": 1 + }, + "status": { + "type": "string", + "enum": [ + "NOT_STARTED", + "PENDING", + "SUCCESS", + "FAILED", + "TEMPORARY_FAILURE" + ] + }, + "region": { "type": "string", "default": "us-east-1" }, + "clickTracking": { "type": "boolean", "default": false }, + "openTracking": { "type": "boolean", "default": false }, + "publicKey": { "type": "string" }, + "dkimStatus": { "type": "string", "nullable": true }, + "spfDetails": { "type": "string", "nullable": true }, + "createdAt": { "type": "string" }, + "updatedAt": { "type": "string" }, + "dmarcAdded": { "type": "boolean", "default": false }, + "isVerifying": { "type": "boolean", "default": false }, + "errorMessage": { "type": "string", "nullable": true }, + "subdomain": { "type": "string", "nullable": true }, + "verificationError": { "type": "string", "nullable": true }, + "lastCheckedTime": { "type": "string", "nullable": true }, + "dnsRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["MX", "TXT"], + "description": "DNS record type", + "example": "TXT" + }, + "name": { + "type": "string", + "description": "DNS record name", + "example": "mail" + }, + "value": { + "type": "string", + "description": "DNS record value", + "example": "v=spf1 include:amazonses.com ~all" + }, + "ttl": { + "type": "string", + "description": "DNS record TTL", + "example": "Auto" + }, + "priority": { + "type": "string", + "nullable": true, + "description": "DNS record priority", + "example": "10" + }, + "status": { + "type": "string", + "enum": [ + "NOT_STARTED", + "PENDING", + "SUCCESS", + "FAILED", + "TEMPORARY_FAILURE" + ] + }, + "recommended": { + "type": "boolean", + "description": "Whether the record is recommended" + } + }, + "required": ["type", "name", "value", "ttl", "status"] + } + } + }, + "required": [ + "id", + "name", + "teamId", + "status", + "publicKey", + "createdAt", + "updatedAt", + "dnsRecords" + ] + } + } + } + } + } + }, + "delete": { + "parameters": [ + { + "schema": { "type": "number", "nullable": true, "example": 1 }, + "required": false, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Domain deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { "type": "number" }, + "success": { "type": "boolean" }, + "message": { "type": "string" } + }, + "required": ["id", "success", "message"] + } + } + } + }, + "403": { + "description": "Forbidden - API key doesn't have access", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "error": { "type": "string" } }, + "required": ["error"] + } + } + } + }, + "404": { + "description": "Domain not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "error": { "type": "string" } }, + "required": ["error"] + } + } + } + } + } + } + }, + "/v1/emails/{emailId}": { + "get": { + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 3, + "example": "cuiwqdj74rygf74" + }, + "required": true, + "name": "emailId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Retrieve the email", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "teamId": { "type": "number" }, + "to": { + "anyOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "replyTo": { + "anyOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "cc": { + "anyOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "bcc": { + "anyOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "from": { "type": "string" }, + "subject": { "type": "string" }, + "html": { "type": "string", "nullable": true }, + "text": { "type": "string", "nullable": true }, + "createdAt": { "type": "string" }, + "updatedAt": { "type": "string" }, + "emailEvents": { + "type": "array", + "items": { + "type": "object", + "properties": { + "emailId": { "type": "string" }, + "status": { + "type": "string", + "enum": [ + "SCHEDULED", + "QUEUED", + "SENT", + "DELIVERY_DELAYED", + "BOUNCED", + "REJECTED", + "RENDERING_FAILURE", + "DELIVERED", + "OPENED", + "CLICKED", + "COMPLAINED", + "FAILED", + "CANCELLED", + "SUPPRESSED" + ] + }, + "createdAt": { "type": "string" }, + "data": { "nullable": true } + }, + "required": ["emailId", "status", "createdAt"] + } + } + }, + "required": [ + "id", + "teamId", + "to", + "from", + "subject", + "html", + "text", + "createdAt", + "updatedAt", + "emailEvents" + ] + } + } + } + } + } + }, + "patch": { + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 3, + "example": "cuiwqdj74rygf74" + }, + "required": true, + "name": "emailId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "scheduledAt": { "type": "string", "format": "date-time" } + }, + "required": ["scheduledAt"] + } + } + } + }, + "responses": { + "200": { + "description": "Retrieve the user", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "emailId": { "type": "string" } } + } + } + } + } + } + } + }, + "/v1/emails": { + "get": { + "parameters": [ + { + "schema": { "type": "string", "default": "1", "example": "1" }, + "required": false, + "name": "page", + "in": "query" + }, + { + "schema": { "type": "string", "default": "50", "example": "50" }, + "required": false, + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "date-time", + "example": "2024-01-01T00:00:00Z" + }, + "required": false, + "name": "startDate", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "date-time", + "example": "2024-01-31T23:59:59Z" + }, + "required": false, + "name": "endDate", + "in": "query" + }, + { + "schema": { + "anyOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ], + "example": "123" + }, + "required": false, + "name": "domainId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Retrieve a list of emails", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "to": { + "anyOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "replyTo": { + "anyOf": [ + { "type": "string" }, + { + "type": "array", + "items": { "type": "string" } + }, + { "nullable": true } + ] + }, + "cc": { + "anyOf": [ + { "type": "string" }, + { + "type": "array", + "items": { "type": "string" } + }, + { "nullable": true } + ] + }, + "bcc": { + "anyOf": [ + { "type": "string" }, + { + "type": "array", + "items": { "type": "string" } + }, + { "nullable": true } + ] + }, + "from": { "type": "string" }, + "subject": { "type": "string" }, + "html": { "type": "string", "nullable": true }, + "text": { "type": "string", "nullable": true }, + "createdAt": { "type": "string" }, + "updatedAt": { "type": "string" }, + "latestStatus": { + "type": "string", + "nullable": true, + "enum": [ + "SCHEDULED", + "QUEUED", + "SENT", + "DELIVERY_DELAYED", + "BOUNCED", + "REJECTED", + "RENDERING_FAILURE", + "DELIVERED", + "OPENED", + "CLICKED", + "COMPLAINED", + "FAILED", + "CANCELLED", + "SUPPRESSED" + ] + }, + "scheduledAt": { + "type": "string", + "nullable": true, + "format": "date-time" + }, + "domainId": { "type": "number", "nullable": true } + }, + "required": [ + "id", + "to", + "from", + "subject", + "html", + "text", + "createdAt", + "updatedAt", + "latestStatus", + "scheduledAt", + "domainId" + ] + } + }, + "count": { "type": "number" } + }, + "required": ["data", "count"] + } + } + } + } + } + }, + "post": { + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "Pass the optional Idempotency-Key header to make the request safe to retry. The key can be up to 256 characters. The server stores the canonical request body and behaves as follows:\n\n- Same key + same request body → returns the original emailId with 200 OK without re-sending.\n- Same key + different request body → returns 409 Conflict with code: NOT_UNIQUE so you can detect the mismatch.\n- Same key while another request is still being processed → returns 409 Conflict; retry after a short delay or once the first request completes.\n\nEntries expire after 24 hours. Use a unique key per logical send (for example, an order or signup ID)." + }, + "required": false, + "name": "Idempotency-Key", + "in": "header" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "to": { + "anyOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "from": { "type": "string" }, + "subject": { + "type": "string", + "minLength": 1, + "description": "Optional when templateId is provided" + }, + "templateId": { + "type": "string", + "description": "ID of a template from the dashboard" + }, + "variables": { + "type": "object", + "additionalProperties": { "type": "string" } + }, + "replyTo": { + "anyOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "cc": { + "anyOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "bcc": { + "anyOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "text": { + "type": "string", + "nullable": true, + "minLength": 1 + }, + "html": { + "type": "string", + "nullable": true, + "minLength": 1 + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string", + "minLength": 1 + }, + "description": "Custom headers to included with the emails" + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filename": { "type": "string", "minLength": 1 }, + "content": { "type": "string", "minLength": 1 } + }, + "required": ["filename", "content"] + }, + "maxItems": 10 + }, + "scheduledAt": { "type": "string", "format": "date-time" }, + "inReplyToId": { "type": "string", "nullable": true } + }, + "required": ["to", "from"] + } + } + } + }, + "responses": { + "200": { + "description": "Retrieve the user", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "emailId": { "type": "string" } } + } + } + } + } + } + } + }, + "/v1/emails/batch": { + "post": { + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256, + "description": "Pass the optional Idempotency-Key header to make the request safe to retry. The key can be up to 256 characters. The server stores the canonical request body and behaves as follows:\n\n- Same key + same request body → returns the original emailId with 200 OK without re-sending.\n- Same key + different request body → returns 409 Conflict with code: NOT_UNIQUE so you can detect the mismatch.\n- Same key while another request is still being processed → returns 409 Conflict; retry after a short delay or once the first request completes.\n\nEntries expire after 24 hours. Use a unique key per logical send (for example, an order or signup ID)." + }, + "required": false, + "name": "Idempotency-Key", + "in": "header" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "to": { + "anyOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "from": { "type": "string" }, + "subject": { + "type": "string", + "minLength": 1, + "description": "Optional when templateId is provided" + }, + "templateId": { + "type": "string", + "description": "ID of a template from the dashboard" + }, + "variables": { + "type": "object", + "additionalProperties": { "type": "string" } + }, + "replyTo": { + "anyOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "cc": { + "anyOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "bcc": { + "anyOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "text": { + "type": "string", + "nullable": true, + "minLength": 1 + }, + "html": { + "type": "string", + "nullable": true, + "minLength": 1 + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string", + "minLength": 1 + }, + "description": "Custom headers to included with the emails" + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filename": { "type": "string", "minLength": 1 }, + "content": { "type": "string", "minLength": 1 } + }, + "required": ["filename", "content"] + }, + "maxItems": 10 + }, + "scheduledAt": { "type": "string", "format": "date-time" }, + "inReplyToId": { "type": "string", "nullable": true } + }, + "required": ["to", "from"] + }, + "maxItems": 100 + } + } + } + }, + "responses": { + "200": { + "description": "List of successfully created email IDs", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { "emailId": { "type": "string" } }, + "required": ["emailId"] + } + } + }, + "required": ["data"] + } + } + } + } + } + } + }, + "/v1/emails/{emailId}/cancel": { + "post": { + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 3, + "example": "cuiwqdj74rygf74" + }, + "required": true, + "name": "emailId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Retrieve the user", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "emailId": { "type": "string" } } + } + } + } + } + } + } + }, + "/v1/contactBooks/{contactBookId}/contacts": { + "post": { + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 3, + "example": "cuiwqdj74rygf74" + }, + "required": true, + "name": "contactBookId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "properties": { + "type": "object", + "additionalProperties": { "type": "string" } + }, + "subscribed": { "type": "boolean" } + }, + "required": ["email"] + } + } + } + }, + "responses": { + "200": { + "description": "Retrieve the user", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "contactId": { "type": "string" } } + } + } + } + } + } + }, + "get": { + "parameters": [ + { + "schema": { "type": "string", "example": "cuiwqdj74rygf74" }, + "required": true, + "name": "contactBookId", + "in": "path" + }, + { + "schema": { "type": "string" }, + "required": false, + "name": "emails", + "in": "query" + }, + { + "schema": { "type": "number" }, + "required": false, + "name": "page", + "in": "query" + }, + { + "schema": { "type": "number" }, + "required": false, + "name": "limit", + "in": "query" + }, + { + "schema": { "type": "string" }, + "required": false, + "name": "ids", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Retrieve multiple contacts", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "firstName": { "type": "string", "nullable": true }, + "lastName": { "type": "string", "nullable": true }, + "email": { "type": "string" }, + "subscribed": { "type": "boolean", "default": true }, + "properties": { + "type": "object", + "additionalProperties": { "type": "string" } + }, + "contactBookId": { "type": "string" }, + "createdAt": { "type": "string" }, + "updatedAt": { "type": "string" } + }, + "required": [ + "id", + "email", + "properties", + "contactBookId", + "createdAt", + "updatedAt" + ] + } + } + } + } + } + } + } + }, + "/v1/contactBooks/{contactBookId}/contacts/{contactId}": { + "patch": { + "parameters": [ + { + "schema": { "type": "string", "example": "cuiwqdj74rygf74" }, + "required": true, + "name": "contactBookId", + "in": "path" + }, + { + "schema": { "type": "string", "example": "cuiwqdj74rygf74" }, + "required": true, + "name": "contactId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "properties": { + "type": "object", + "additionalProperties": { "type": "string" } + }, + "subscribed": { "type": "boolean" } + } + } + } + } + }, + "responses": { + "200": { + "description": "Retrieve the user", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "contactId": { "type": "string" } } + } + } + } + } + } + }, + "get": { + "parameters": [ + { + "schema": { "type": "string", "example": "cuiwqdj74rygf74" }, + "required": true, + "name": "contactBookId", + "in": "path" + }, + { + "schema": { "type": "string", "example": "cuiwqdj74rygf74" }, + "required": true, + "name": "contactId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Retrieve the contact", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "firstName": { "type": "string", "nullable": true }, + "lastName": { "type": "string", "nullable": true }, + "email": { "type": "string" }, + "subscribed": { "type": "boolean", "default": true }, + "properties": { + "type": "object", + "additionalProperties": { "type": "string" } + }, + "contactBookId": { "type": "string" }, + "createdAt": { "type": "string" }, + "updatedAt": { "type": "string" } + }, + "required": [ + "id", + "email", + "properties", + "contactBookId", + "createdAt", + "updatedAt" + ] + } + } + } + } + } + }, + "put": { + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 3, + "example": "cuiwqdj74rygf74" + }, + "required": true, + "name": "contactBookId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "properties": { + "type": "object", + "additionalProperties": { "type": "string" } + }, + "subscribed": { "type": "boolean" } + }, + "required": ["email"] + } + } + } + }, + "responses": { + "200": { + "description": "Contact upserted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "contactId": { "type": "string" } }, + "required": ["contactId"] + } + } + } + } + } + }, + "delete": { + "parameters": [ + { + "schema": { "type": "string", "example": "cuiwqdj74rygf74" }, + "required": true, + "name": "contactBookId", + "in": "path" + }, + { + "schema": { "type": "string", "example": "cuiwqdj74rygf74" }, + "required": true, + "name": "contactId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Contact deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "success": { "type": "boolean" } }, + "required": ["success"] + } + } + } + } + } + } + }, + "/v1/contactBooks/{contactBookId}/contacts/bulk": { + "post": { + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 3, + "example": "cuiwqdj74rygf74" + }, + "required": true, + "name": "contactBookId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "properties": { + "type": "object", + "additionalProperties": { "type": "string" } + }, + "subscribed": { "type": "boolean" } + }, + "required": ["email"] + }, + "maxItems": 1000 + } + } + } + }, + "responses": { + "200": { + "description": "Bulk add contacts to a contact book", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" }, + "count": { "type": "number" } + }, + "required": ["message", "count"] + } + } + } + } + } + }, + "delete": { + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 3, + "example": "cuiwqdj74rygf74" + }, + "required": true, + "name": "contactBookId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "contactIds": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1, + "maxItems": 1000 + } + }, + "required": ["contactIds"] + } + } + } + }, + "responses": { + "200": { + "description": "Bulk delete contacts from a contact book", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean" }, + "count": { "type": "number" } + }, + "required": ["success", "count"] + } + } + } + } + } + } + }, + "/v1/contactBooks": { + "get": { + "responses": { + "200": { + "description": "Retrieve contact books accessible by the API key", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The ID of the contact book", + "example": "clx1234567890" + }, + "name": { + "type": "string", + "description": "The name of the contact book", + "example": "Newsletter Subscribers" + }, + "teamId": { + "type": "number", + "description": "The ID of the team", + "example": 1 + }, + "properties": { + "type": "object", + "additionalProperties": { "type": "string" }, + "description": "Custom properties for the contact book", + "example": { "customField1": "value1" } + }, + "variables": { + "type": "array", + "items": { "type": "string" }, + "description": "Allowed personalization variables for contacts in this book", + "example": ["registrationCode", "company"] + }, + "emoji": { + "type": "string", + "description": "The emoji associated with the contact book", + "example": "📙" + }, + "doubleOptInEnabled": { + "type": "boolean", + "description": "Whether double opt-in is enabled for new contacts", + "example": true + }, + "doubleOptInFrom": { + "type": "string", + "nullable": true, + "description": "From address used for double opt-in emails (must use a verified domain)", + "example": "Newsletter " + }, + "doubleOptInSubject": { + "type": "string", + "nullable": true, + "description": "Subject line used for double opt-in confirmation email", + "example": "Please confirm your subscription" + }, + "doubleOptInContent": { + "type": "string", + "nullable": true, + "description": "Email editor JSON content used for double opt-in confirmation" + }, + "createdAt": { + "type": "string", + "description": "The creation timestamp" + }, + "updatedAt": { + "type": "string", + "description": "The last update timestamp" + }, + "_count": { + "type": "object", + "properties": { + "contacts": { + "type": "number", + "description": "The number of contacts in the contact book" + } + }, + "required": ["contacts"] + } + }, + "required": [ + "id", + "name", + "teamId", + "properties", + "variables", + "emoji", + "createdAt", + "updatedAt" + ] + } + } + } + } + } + } + }, + "post": { + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { "type": "string", "minLength": 1 }, + "emoji": { "type": "string" }, + "properties": { + "type": "object", + "additionalProperties": { "type": "string" } + }, + "doubleOptInEnabled": { "type": "boolean" }, + "doubleOptInFrom": { "type": "string", "nullable": true }, + "doubleOptInSubject": { "type": "string" }, + "doubleOptInContent": { "type": "string" }, + "variables": { + "type": "array", + "items": { "type": "string" } + } + }, + "required": ["name"] + } + } + } + }, + "responses": { + "200": { + "description": "Create a new contact book", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The ID of the contact book", + "example": "clx1234567890" + }, + "name": { + "type": "string", + "description": "The name of the contact book", + "example": "Newsletter Subscribers" + }, + "teamId": { + "type": "number", + "description": "The ID of the team", + "example": 1 + }, + "properties": { + "type": "object", + "additionalProperties": { "type": "string" }, + "description": "Custom properties for the contact book", + "example": { "customField1": "value1" } + }, + "variables": { + "type": "array", + "items": { "type": "string" }, + "description": "Allowed personalization variables for contacts in this book", + "example": ["registrationCode", "company"] + }, + "emoji": { + "type": "string", + "description": "The emoji associated with the contact book", + "example": "📙" + }, + "doubleOptInEnabled": { + "type": "boolean", + "description": "Whether double opt-in is enabled for new contacts", + "example": true + }, + "doubleOptInFrom": { + "type": "string", + "nullable": true, + "description": "From address used for double opt-in emails (must use a verified domain)", + "example": "Newsletter " + }, + "doubleOptInSubject": { + "type": "string", + "nullable": true, + "description": "Subject line used for double opt-in confirmation email", + "example": "Please confirm your subscription" + }, + "doubleOptInContent": { + "type": "string", + "nullable": true, + "description": "Email editor JSON content used for double opt-in confirmation" + }, + "createdAt": { + "type": "string", + "description": "The creation timestamp" + }, + "updatedAt": { + "type": "string", + "description": "The last update timestamp" + }, + "_count": { + "type": "object", + "properties": { + "contacts": { + "type": "number", + "description": "The number of contacts in the contact book" + } + }, + "required": ["contacts"] + } + }, + "required": [ + "id", + "name", + "teamId", + "properties", + "variables", + "emoji", + "createdAt", + "updatedAt" + ] + } + } + } + } + } + } + }, + "/v1/contactBooks/{contactBookId}": { + "get": { + "parameters": [ + { + "schema": { "type": "string", "example": "clx1234567890" }, + "required": true, + "name": "contactBookId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Retrieve the contact book", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The ID of the contact book", + "example": "clx1234567890" + }, + "name": { + "type": "string", + "description": "The name of the contact book", + "example": "Newsletter Subscribers" + }, + "teamId": { + "type": "number", + "description": "The ID of the team", + "example": 1 + }, + "properties": { + "type": "object", + "additionalProperties": { "type": "string" }, + "description": "Custom properties for the contact book", + "example": { "customField1": "value1" } + }, + "variables": { + "type": "array", + "items": { "type": "string" }, + "description": "Allowed personalization variables for contacts in this book", + "example": ["registrationCode", "company"] + }, + "emoji": { + "type": "string", + "description": "The emoji associated with the contact book", + "example": "📙" + }, + "doubleOptInEnabled": { + "type": "boolean", + "description": "Whether double opt-in is enabled for new contacts", + "example": true + }, + "doubleOptInFrom": { + "type": "string", + "nullable": true, + "description": "From address used for double opt-in emails (must use a verified domain)", + "example": "Newsletter " + }, + "doubleOptInSubject": { + "type": "string", + "nullable": true, + "description": "Subject line used for double opt-in confirmation email", + "example": "Please confirm your subscription" + }, + "doubleOptInContent": { + "type": "string", + "nullable": true, + "description": "Email editor JSON content used for double opt-in confirmation" + }, + "createdAt": { + "type": "string", + "description": "The creation timestamp" + }, + "updatedAt": { + "type": "string", + "description": "The last update timestamp" + }, + "_count": { + "type": "object", + "properties": { + "contacts": { + "type": "number", + "description": "The number of contacts in the contact book" + } + }, + "required": ["contacts"] + } + }, + "required": [ + "id", + "name", + "teamId", + "properties", + "variables", + "emoji", + "createdAt", + "updatedAt" + ] + } + } + } + }, + "403": { + "description": "Forbidden - API key doesn't have access to this contact book", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "error": { "type": "string" } }, + "required": ["error"] + } + } + } + }, + "404": { + "description": "Contact book not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "error": { "type": "string" } }, + "required": ["error"] + } + } + } + } + } + }, + "patch": { + "parameters": [ + { + "schema": { "type": "string", "example": "clx1234567890" }, + "required": true, + "name": "contactBookId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { "type": "string", "minLength": 1 }, + "emoji": { "type": "string" }, + "properties": { + "type": "object", + "additionalProperties": { "type": "string" } + }, + "doubleOptInEnabled": { "type": "boolean" }, + "doubleOptInFrom": { "type": "string", "nullable": true }, + "doubleOptInSubject": { "type": "string" }, + "doubleOptInContent": { "type": "string" }, + "variables": { + "type": "array", + "items": { "type": "string" } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Update the contact book", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The ID of the contact book", + "example": "clx1234567890" + }, + "name": { + "type": "string", + "description": "The name of the contact book", + "example": "Newsletter Subscribers" + }, + "teamId": { + "type": "number", + "description": "The ID of the team", + "example": 1 + }, + "properties": { + "type": "object", + "additionalProperties": { "type": "string" }, + "description": "Custom properties for the contact book", + "example": { "customField1": "value1" } + }, + "variables": { + "type": "array", + "items": { "type": "string" }, + "description": "Allowed personalization variables for contacts in this book", + "example": ["registrationCode", "company"] + }, + "emoji": { + "type": "string", + "description": "The emoji associated with the contact book", + "example": "📙" + }, + "doubleOptInEnabled": { + "type": "boolean", + "description": "Whether double opt-in is enabled for new contacts", + "example": true + }, + "doubleOptInFrom": { + "type": "string", + "nullable": true, + "description": "From address used for double opt-in emails (must use a verified domain)", + "example": "Newsletter " + }, + "doubleOptInSubject": { + "type": "string", + "nullable": true, + "description": "Subject line used for double opt-in confirmation email", + "example": "Please confirm your subscription" + }, + "doubleOptInContent": { + "type": "string", + "nullable": true, + "description": "Email editor JSON content used for double opt-in confirmation" + }, + "createdAt": { + "type": "string", + "description": "The creation timestamp" + }, + "updatedAt": { + "type": "string", + "description": "The last update timestamp" + }, + "_count": { + "type": "object", + "properties": { + "contacts": { + "type": "number", + "description": "The number of contacts in the contact book" + } + }, + "required": ["contacts"] + } + }, + "required": [ + "id", + "name", + "teamId", + "properties", + "variables", + "emoji", + "createdAt", + "updatedAt" + ] + } + } + } + }, + "403": { + "description": "Forbidden - API key doesn't have access to this contact book", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "error": { "type": "string" } }, + "required": ["error"] + } + } + } + }, + "404": { + "description": "Contact book not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "error": { "type": "string" } }, + "required": ["error"] + } + } + } + } + } + }, + "delete": { + "parameters": [ + { + "schema": { "type": "string", "example": "clx1234567890" }, + "required": true, + "name": "contactBookId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Contact book deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "success": { "type": "boolean" }, + "message": { "type": "string" } + }, + "required": ["id", "success", "message"] + } + } + } + }, + "403": { + "description": "Forbidden - API key doesn't have access", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "error": { "type": "string" } }, + "required": ["error"] + } + } + } + }, + "404": { + "description": "Contact book not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "error": { "type": "string" } }, + "required": ["error"] + } + } + } + } + } + } + }, + "/v1/campaigns": { + "post": { + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { "type": "string", "minLength": 1 }, + "from": { "type": "string", "minLength": 1 }, + "subject": { "type": "string", "minLength": 1 }, + "previewText": { "type": "string" }, + "contactBookId": { "type": "string", "minLength": 1 }, + "content": { "type": "string", "minLength": 1 }, + "html": { "type": "string", "minLength": 1 }, + "replyTo": { + "anyOf": [ + { "type": "string", "minLength": 1 }, + { + "type": "array", + "items": { "type": "string", "minLength": 1 } + } + ] + }, + "cc": { + "anyOf": [ + { "type": "string", "minLength": 1 }, + { + "type": "array", + "items": { "type": "string", "minLength": 1 } + } + ] + }, + "bcc": { + "anyOf": [ + { "type": "string", "minLength": 1 }, + { + "type": "array", + "items": { "type": "string", "minLength": 1 } + } + ] + }, + "sendNow": { "type": "boolean" }, + "scheduledAt": { + "type": "string", + "description": "Timestamp in ISO 8601 format or natural language (e.g., 'tomorrow 9am', 'next monday 10:30')" + }, + "batchSize": { + "type": "integer", + "minimum": 1, + "maximum": 100000 + } + }, + "required": ["name", "from", "subject", "contactBookId"] + } + } + } + }, + "responses": { + "200": { + "description": "Create a campaign", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "from": { "type": "string" }, + "subject": { "type": "string" }, + "previewText": { "type": "string", "nullable": true }, + "contactBookId": { "type": "string", "nullable": true }, + "html": { "type": "string", "nullable": true }, + "content": { "type": "string", "nullable": true }, + "status": { "type": "string" }, + "scheduledAt": { + "type": "string", + "nullable": true, + "format": "date-time" + }, + "batchSize": { "type": "integer" }, + "batchWindowMinutes": { "type": "integer" }, + "total": { "type": "integer" }, + "sent": { "type": "integer" }, + "delivered": { "type": "integer" }, + "opened": { "type": "integer" }, + "clicked": { "type": "integer" }, + "unsubscribed": { "type": "integer" }, + "bounced": { "type": "integer" }, + "hardBounced": { "type": "integer" }, + "complained": { "type": "integer" }, + "replyTo": { + "type": "array", + "items": { "type": "string" } + }, + "cc": { "type": "array", "items": { "type": "string" } }, + "bcc": { "type": "array", "items": { "type": "string" } }, + "createdAt": { "type": "string", "format": "date-time" }, + "updatedAt": { "type": "string", "format": "date-time" } + }, + "required": [ + "id", + "name", + "from", + "subject", + "previewText", + "contactBookId", + "html", + "content", + "status", + "scheduledAt", + "batchSize", + "batchWindowMinutes", + "total", + "sent", + "delivered", + "opened", + "clicked", + "unsubscribed", + "bounced", + "hardBounced", + "complained", + "replyTo", + "cc", + "bcc", + "createdAt", + "updatedAt" + ] + } + } + } + } + } + }, + "get": { + "parameters": [ + { + "schema": { + "type": "string", + "description": "Page number for pagination (default: 1)", + "example": "1" + }, + "required": false, + "name": "page", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": ["DRAFT", "SCHEDULED", "RUNNING", "PAUSED", "SENT"], + "description": "Filter campaigns by status", + "example": "DRAFT" + }, + "required": false, + "name": "status", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Search campaigns by name or subject", + "example": "newsletter" + }, + "required": false, + "name": "search", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Get list of campaigns", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "campaigns": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "from": { "type": "string" }, + "subject": { "type": "string" }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "status": { "type": "string" }, + "scheduledAt": { + "type": "string", + "nullable": true, + "format": "date-time" + }, + "total": { "type": "integer" }, + "sent": { "type": "integer" }, + "delivered": { "type": "integer" }, + "unsubscribed": { "type": "integer" } + }, + "required": [ + "id", + "name", + "from", + "subject", + "createdAt", + "updatedAt", + "status", + "scheduledAt", + "total", + "sent", + "delivered", + "unsubscribed" + ] + } + }, + "totalPage": { "type": "integer" } + }, + "required": ["campaigns", "totalPage"] + } + } + } + } + } + } + }, + "/v1/campaigns/{campaignId}": { + "get": { + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "example": "cmp_123" + }, + "required": true, + "name": "campaignId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Get campaign details", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "from": { "type": "string" }, + "subject": { "type": "string" }, + "previewText": { "type": "string", "nullable": true }, + "contactBookId": { "type": "string", "nullable": true }, + "html": { "type": "string", "nullable": true }, + "content": { "type": "string", "nullable": true }, + "status": { "type": "string" }, + "scheduledAt": { + "type": "string", + "nullable": true, + "format": "date-time" + }, + "batchSize": { "type": "integer" }, + "batchWindowMinutes": { "type": "integer" }, + "total": { "type": "integer" }, + "sent": { "type": "integer" }, + "delivered": { "type": "integer" }, + "opened": { "type": "integer" }, + "clicked": { "type": "integer" }, + "unsubscribed": { "type": "integer" }, + "bounced": { "type": "integer" }, + "hardBounced": { "type": "integer" }, + "complained": { "type": "integer" }, + "replyTo": { + "type": "array", + "items": { "type": "string" } + }, + "cc": { "type": "array", "items": { "type": "string" } }, + "bcc": { "type": "array", "items": { "type": "string" } }, + "createdAt": { "type": "string", "format": "date-time" }, + "updatedAt": { "type": "string", "format": "date-time" } + }, + "required": [ + "id", + "name", + "from", + "subject", + "previewText", + "contactBookId", + "html", + "content", + "status", + "scheduledAt", + "batchSize", + "batchWindowMinutes", + "total", + "sent", + "delivered", + "opened", + "clicked", + "unsubscribed", + "bounced", + "hardBounced", + "complained", + "replyTo", + "cc", + "bcc", + "createdAt", + "updatedAt" + ] + } + } + } + } + } + }, + "delete": { + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "example": "cmp_123" + }, + "required": true, + "name": "campaignId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Delete campaign", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "from": { "type": "string" }, + "subject": { "type": "string" }, + "previewText": { "type": "string", "nullable": true }, + "contactBookId": { "type": "string", "nullable": true }, + "html": { "type": "string", "nullable": true }, + "content": { "type": "string", "nullable": true }, + "status": { "type": "string" }, + "scheduledAt": { + "type": "string", + "nullable": true, + "format": "date-time" + }, + "batchSize": { "type": "integer" }, + "batchWindowMinutes": { "type": "integer" }, + "total": { "type": "integer" }, + "sent": { "type": "integer" }, + "delivered": { "type": "integer" }, + "opened": { "type": "integer" }, + "clicked": { "type": "integer" }, + "unsubscribed": { "type": "integer" }, + "bounced": { "type": "integer" }, + "hardBounced": { "type": "integer" }, + "complained": { "type": "integer" }, + "replyTo": { + "type": "array", + "items": { "type": "string" } + }, + "cc": { "type": "array", "items": { "type": "string" } }, + "bcc": { "type": "array", "items": { "type": "string" } }, + "createdAt": { "type": "string", "format": "date-time" }, + "updatedAt": { "type": "string", "format": "date-time" } + }, + "required": [ + "id", + "name", + "from", + "subject", + "previewText", + "contactBookId", + "html", + "content", + "status", + "scheduledAt", + "batchSize", + "batchWindowMinutes", + "total", + "sent", + "delivered", + "opened", + "clicked", + "unsubscribed", + "bounced", + "hardBounced", + "complained", + "replyTo", + "cc", + "bcc", + "createdAt", + "updatedAt" + ] + } + } + } + } + } + } + }, + "/v1/campaigns/{campaignId}/schedule": { + "post": { + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "example": "cmp_123" + }, + "required": true, + "name": "campaignId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "scheduledAt": { + "type": "string", + "description": "Timestamp in ISO 8601 format or natural language (e.g., 'tomorrow 9am', 'next monday 10:30')" + }, + "batchSize": { + "type": "integer", + "minimum": 1, + "maximum": 100000 + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Schedule a campaign", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "success": { "type": "boolean" } }, + "required": ["success"] + } + } + } + } + } + } + }, + "/v1/campaigns/{campaignId}/pause": { + "post": { + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "example": "cmp_123" + }, + "required": true, + "name": "campaignId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Pause a campaign", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "success": { "type": "boolean" } }, + "required": ["success"] + } + } + } + } + } + } + }, + "/v1/campaigns/{campaignId}/resume": { + "post": { + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "example": "cmp_123" + }, + "required": true, + "name": "campaignId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Resume a campaign", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "success": { "type": "boolean" } }, + "required": ["success"] + } + } + } + } + } + } + }, + "/v1/analytics/email-time-series": { + "get": { + "parameters": [ + { + "schema": { + "type": "string", + "enum": ["7", "30"], + "description": "Number of days to retrieve data for (default: 30)", + "example": "30" + }, + "required": false, + "name": "days", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by domain ID" + }, + "required": false, + "name": "domainId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Retrieve email time series data", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "result": { + "type": "array", + "items": { + "type": "object", + "properties": { + "date": { "type": "string" }, + "sent": { "type": "integer" }, + "delivered": { "type": "integer" }, + "opened": { "type": "integer" }, + "clicked": { "type": "integer" }, + "bounced": { "type": "integer" }, + "complained": { "type": "integer" } + }, + "required": [ + "date", + "sent", + "delivered", + "opened", + "clicked", + "bounced", + "complained" + ] + } + }, + "totalCounts": { + "type": "object", + "properties": { + "sent": { "type": "integer" }, + "delivered": { "type": "integer" }, + "opened": { "type": "integer" }, + "clicked": { "type": "integer" }, + "bounced": { "type": "integer" }, + "complained": { "type": "integer" } + }, + "required": [ + "sent", + "delivered", + "opened", + "clicked", + "bounced", + "complained" + ] + } + }, + "required": ["result", "totalCounts"] + } + } + } + } + } + } + }, + "/v1/analytics/reputation-metrics": { + "get": { + "parameters": [ + { + "schema": { + "type": "string", + "description": "Filter by domain ID" + }, + "required": false, + "name": "domainId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Retrieve reputation metrics data", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "delivered": { "type": "integer" }, + "hardBounced": { "type": "integer" }, + "complained": { "type": "integer" }, + "bounceRate": { "type": "number" }, + "complaintRate": { "type": "number" } + }, + "required": [ + "delivered", + "hardBounced", + "complained", + "bounceRate", + "complaintRate" + ] + } + } + } + } + } + } + } + } } diff --git a/packages/python-sdk/README.md b/packages/python-sdk/README.md index 5605cc8..ab1c404 100644 --- a/packages/python-sdk/README.md +++ b/packages/python-sdk/README.md @@ -100,7 +100,8 @@ It is published as `usesend` on PyPI. ## Available Resources - **Emails**: `client.emails.send()`, `client.emails.get()` -- **Contacts**: `client.contacts.create()`, `client.contacts.get()`, `client.contacts.list()` +- **ContactBooks**: `client.contact_books.list()`, `client.contact_books.create()`, `client.contact_books.get()`, `client.contact_books.update()` +- **Contacts**: `client.contacts.create()`, `client.contacts.list()`, `client.contacts.get()`, `client.contacts.bulk_create()`, `client.contacts.bulk_delete()` - **Domains**: `client.domains.create()`, `client.domains.get()`, `client.domains.verify()` - **Campaigns**: `client.campaigns.create()`, `client.campaigns.get()`, `client.campaigns.schedule()`, `client.campaigns.pause()`, `client.campaigns.resume()` diff --git a/packages/python-sdk/pyproject.toml b/packages/python-sdk/pyproject.toml index faee6a5..47dc456 100644 --- a/packages/python-sdk/pyproject.toml +++ b/packages/python-sdk/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "usesend" -version = "0.2.9" +version = "0.2.10" description = "Python SDK for the UseSend API" authors = ["UseSend"] license = "MIT" @@ -14,6 +14,7 @@ requests = "^2.32.0" typing_extensions = ">=4.7" [tool.poetry.group.dev.dependencies] +pytest = "^8.3.5" [build-system] requires = ["poetry-core"] diff --git a/packages/python-sdk/tests/test_resources.py b/packages/python-sdk/tests/test_resources.py new file mode 100644 index 0000000..65eec5b --- /dev/null +++ b/packages/python-sdk/tests/test_resources.py @@ -0,0 +1,138 @@ +from typing import Any, Dict, List, Optional + +from usesend import UseSend + + +class MockResponse: + def __init__(self, payload: Dict[str, Any], ok: bool = True, reason: str = "OK") -> None: + self._payload = payload + self.ok = ok + self.reason = reason + self.status_code = 200 if ok else 400 + + def json(self) -> Dict[str, Any]: + return self._payload + + +class MockSession: + def __init__(self, responses: List[MockResponse]) -> None: + self._responses = responses + self.calls: List[Dict[str, Any]] = [] + + def request( + self, + method: str, + url: str, + headers: Optional[Dict[str, str]] = None, + json: Optional[Any] = None, + ) -> MockResponse: + self.calls.append( + { + "method": method, + "url": url, + "headers": headers, + "json": json, + } + ) + return self._responses.pop(0) + + +def test_contact_books_list_uses_expected_path_and_returns_data() -> None: + session = MockSession( + [ + MockResponse( + [ + { + "id": "cb_123", + "name": "Newsletter Subscribers", + "teamId": 1, + "properties": {}, + "variables": ["company"], + "emoji": "📙", + "doubleOptInEnabled": True, + "doubleOptInFrom": "Newsletter ", + "doubleOptInSubject": "Please confirm your subscription", + "doubleOptInContent": "{}", + "createdAt": "2026-03-01T00:00:00.000Z", + "updatedAt": "2026-03-01T00:00:00.000Z", + "_count": {"contacts": 12}, + } + ] + ) + ] + ) + client = UseSend("us_test", session=session) + + data, err = client.contact_books.list() + + assert err is None + assert data is not None + assert data[0]["variables"] == ["company"] + assert session.calls[0]["method"] == "GET" + assert session.calls[0]["url"].endswith("/api/v1/contactBooks") + + +def test_contact_books_alias_matches_js_style_client() -> None: + session = MockSession([MockResponse({"id": "cb_123", "name": "Book"})]) + client = UseSend("us_test", session=session) + + data, err = client.contactBooks.get("cb_123") + + assert err is None + assert data is not None + assert data["id"] == "cb_123" + assert session.calls[0]["url"].endswith("/api/v1/contactBooks/cb_123") + + +def test_contacts_list_encodes_query_params() -> None: + session = MockSession([MockResponse([])]) + client = UseSend("us_test", session=session) + + data, err = client.contacts.list( + "cb_123", + emails="a@example.com,b@example.com", + page=2, + limit=50, + ids="ct_1,ct_2", + ) + + assert err is None + assert data == [] + assert session.calls[0]["method"] == "GET" + assert session.calls[0]["url"].endswith( + "/api/v1/contactBooks/cb_123/contacts?emails=a%40example.com%2Cb%40example.com&page=2&limit=50&ids=ct_1%2Cct_2" + ) + + +def test_contacts_bulk_methods_use_expected_payloads() -> None: + session = MockSession( + [ + MockResponse({"message": "Contacts imported", "count": 2}), + MockResponse({"success": True, "count": 2}), + ] + ) + client = UseSend("us_test", session=session) + + create_data, create_err = client.contacts.bulk_create( + "cb_123", + [ + {"email": "a@example.com"}, + {"email": "b@example.com", "firstName": "B"}, + ], + ) + delete_data, delete_err = client.contacts.bulk_delete( + "cb_123", + {"contactIds": ["ct_1", "ct_2"]}, + ) + + assert create_err is None + assert create_data == {"message": "Contacts imported", "count": 2} + assert delete_err is None + assert delete_data == {"success": True, "count": 2} + assert session.calls[0]["method"] == "POST" + assert session.calls[0]["json"] == [ + {"email": "a@example.com"}, + {"email": "b@example.com", "firstName": "B"}, + ] + assert session.calls[1]["method"] == "DELETE" + assert session.calls[1]["json"] == {"contactIds": ["ct_1", "ct_2"]} diff --git a/packages/python-sdk/usesend/__init__.py b/packages/python-sdk/usesend/__init__.py index f3bb914..91e3c8c 100644 --- a/packages/python-sdk/usesend/__init__.py +++ b/packages/python-sdk/usesend/__init__.py @@ -1,6 +1,8 @@ """Python client for the UseSend API.""" from .usesend import UseSend, UseSendHTTPError +from .contacts import Contacts # type: ignore +from .contact_books import ContactBooks # type: ignore from .domains import Domains # type: ignore from .campaigns import Campaigns # type: ignore from .webhooks import ( @@ -17,6 +19,8 @@ __all__ = [ "UseSend", "UseSendHTTPError", "types", + "Contacts", + "ContactBooks", "Domains", "Campaigns", "Webhooks", diff --git a/packages/python-sdk/usesend/contact_books.py b/packages/python-sdk/usesend/contact_books.py new file mode 100644 index 0000000..3ff1a6f --- /dev/null +++ b/packages/python-sdk/usesend/contact_books.py @@ -0,0 +1,50 @@ +"""Contact book resource client using TypedDict shapes (no Pydantic).""" +from __future__ import annotations + +from typing import Optional, Tuple, List + +from .types import ( + APIError, + ContactBook, + ContactBookCreate, + ContactBookCreateResponse, + ContactBookDeleteResponse, + ContactBookUpdate, + ContactBookUpdateResponse, +) + + +class ContactBooks: + """Client for `/contactBooks` endpoints.""" + + def __init__(self, usesend: "UseSend") -> None: + self.usesend = usesend + + def list(self) -> Tuple[Optional[List[ContactBook]], Optional[APIError]]: + data, err = self.usesend.get("/contactBooks") + return (data, err) # type: ignore[return-value] + + def create( + self, payload: ContactBookCreate + ) -> Tuple[Optional[ContactBookCreateResponse], Optional[APIError]]: + data, err = self.usesend.post("/contactBooks", payload) + return (data, err) # type: ignore[return-value] + + def get(self, contact_book_id: str) -> Tuple[Optional[ContactBook], Optional[APIError]]: + data, err = self.usesend.get(f"/contactBooks/{contact_book_id}") + return (data, err) # type: ignore[return-value] + + def update( + self, contact_book_id: str, payload: ContactBookUpdate + ) -> Tuple[Optional[ContactBookUpdateResponse], Optional[APIError]]: + data, err = self.usesend.patch(f"/contactBooks/{contact_book_id}", payload) + return (data, err) # type: ignore[return-value] + + def delete( + self, contact_book_id: str + ) -> Tuple[Optional[ContactBookDeleteResponse], Optional[APIError]]: + data, err = self.usesend.delete(f"/contactBooks/{contact_book_id}") + return (data, err) # type: ignore[return-value] + + +from .usesend import UseSend # noqa: E402 pylint: disable=wrong-import-position diff --git a/packages/python-sdk/usesend/contacts.py b/packages/python-sdk/usesend/contacts.py index 088d1a4..4e5c511 100644 --- a/packages/python-sdk/usesend/contacts.py +++ b/packages/python-sdk/usesend/contacts.py @@ -2,11 +2,17 @@ from __future__ import annotations from typing import Any, Dict, Optional, Tuple +from urllib.parse import urlencode from .types import ( APIError, ContactDeleteResponse, Contact, + ContactBulkCreate, + ContactBulkCreateResponse, + ContactBulkDelete, + ContactBulkDeleteResponse, + ContactList, ContactUpdate, ContactUpdateResponse, ContactUpsert, @@ -31,6 +37,32 @@ class Contacts: ) return (data, err) # type: ignore[return-value] + def list( + self, + book_id: str, + *, + emails: Optional[str] = None, + page: Optional[int] = None, + limit: Optional[int] = None, + ids: Optional[str] = None, + ) -> Tuple[Optional[ContactList], Optional[APIError]]: + query: Dict[str, Any] = {} + if emails is not None: + query["emails"] = emails + if page is not None: + query["page"] = page + if limit is not None: + query["limit"] = limit + if ids is not None: + query["ids"] = ids + + path = f"/contactBooks/{book_id}/contacts" + if query: + path = f"{path}?{urlencode(query)}" + + data, err = self.usesend.get(path) + return (data, err) # type: ignore[return-value] + def get( self, book_id: str, contact_id: str ) -> Tuple[Optional[Contact], Optional[APIError]]: @@ -57,6 +89,24 @@ class Contacts: ) return (data, err) # type: ignore[return-value] + def bulk_create( + self, book_id: str, payload: ContactBulkCreate + ) -> Tuple[Optional[ContactBulkCreateResponse], Optional[APIError]]: + data, err = self.usesend.post( + f"/contactBooks/{book_id}/contacts/bulk", + payload, + ) + return (data, err) # type: ignore[return-value] + + def bulk_delete( + self, book_id: str, payload: ContactBulkDelete + ) -> Tuple[Optional[ContactBulkDeleteResponse], Optional[APIError]]: + data, err = self.usesend.delete( + f"/contactBooks/{book_id}/contacts/bulk", + payload, + ) + return (data, err) # type: ignore[return-value] + def delete( self, *, book_id: str, contact_id: str ) -> Tuple[Optional[ContactDeleteResponse], Optional[APIError]]: diff --git a/packages/python-sdk/usesend/types.py b/packages/python-sdk/usesend/types.py index f5c9553..d0a697b 100644 --- a/packages/python-sdk/usesend/types.py +++ b/packages/python-sdk/usesend/types.py @@ -271,6 +271,65 @@ class EmailCancelResponse(TypedDict, total=False): # --------------------------------------------------------------------------- +class ContactBookCounts(TypedDict, total=False): + contacts: int + + +class ContactBook(TypedDict, total=False): + id: str + name: str + teamId: float + properties: Dict[str, str] + variables: List[str] + emoji: str + doubleOptInEnabled: Optional[bool] + doubleOptInFrom: Optional[str] + doubleOptInSubject: Optional[str] + doubleOptInContent: Optional[str] + createdAt: str + updatedAt: str + _count: ContactBookCounts + + +ContactBookList = List[ContactBook] + + +class ContactBookCreate(TypedDict, total=False): + name: str + emoji: Optional[str] + properties: Optional[Dict[str, str]] + doubleOptInEnabled: Optional[bool] + doubleOptInFrom: Optional[str] + doubleOptInSubject: Optional[str] + doubleOptInContent: Optional[str] + variables: Optional[List[str]] + + +class ContactBookCreateResponse(ContactBook, total=False): + pass + + +class ContactBookUpdate(TypedDict, total=False): + name: Optional[str] + emoji: Optional[str] + properties: Optional[Dict[str, str]] + doubleOptInEnabled: Optional[bool] + doubleOptInFrom: Optional[str] + doubleOptInSubject: Optional[str] + doubleOptInContent: Optional[str] + variables: Optional[List[str]] + + +class ContactBookUpdateResponse(ContactBook, total=False): + pass + + +class ContactBookDeleteResponse(TypedDict): + id: str + success: bool + message: str + + class ContactCreate(TypedDict, total=False): email: str firstName: Optional[str] @@ -298,6 +357,23 @@ class ContactListItem(TypedDict, total=False): ContactList = List[ContactListItem] +ContactBulkCreate = List[ContactCreate] + + +class ContactBulkCreateResponse(TypedDict): + message: str + count: float + + +class ContactBulkDelete(TypedDict): + contactIds: List[str] + + +class ContactBulkDeleteResponse(TypedDict): + success: bool + count: float + + class ContactUpdate(TypedDict, total=False): firstName: Optional[str] lastName: Optional[str] diff --git a/packages/python-sdk/usesend/usesend.py b/packages/python-sdk/usesend/usesend.py index 471b40c..8eb94b0 100644 --- a/packages/python-sdk/usesend/usesend.py +++ b/packages/python-sdk/usesend/usesend.py @@ -71,6 +71,8 @@ class UseSend: # Lazily initialise resource clients. self.emails = Emails(self) self.contacts = Contacts(self) + self.contact_books = ContactBooks(self) + self.contactBooks = self.contact_books self.domains = Domains(self) self.campaigns = Campaigns(self) @@ -186,6 +188,7 @@ class UseSend: # Import here to avoid circular dependency during type checking from .emails import Emails # noqa: E402 pylint: disable=wrong-import-position from .contacts import Contacts # noqa: E402 pylint: disable=wrong-import-position +from .contact_books import ContactBooks # noqa: E402 pylint: disable=wrong-import-position from .domains import Domains # type: ignore # noqa: E402 from .campaigns import Campaigns # type: ignore # noqa: E402 from .webhooks import Webhooks # noqa: E402 pylint: disable=wrong-import-position diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 02a2ad6..8c11314 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "usesend-js", - "version": "1.6.2", + "version": "1.6.3", "description": "", "repository": { "type": "git", diff --git a/packages/sdk/types/schema.d.ts b/packages/sdk/types/schema.d.ts index fe76251..b2a44ab 100644 --- a/packages/sdk/types/schema.d.ts +++ b/packages/sdk/types/schema.d.ts @@ -728,300 +728,6 @@ export interface paths { patch?: never; trace?: never; }; - "/v1/contactBooks": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Retrieve contact books accessible by the API key */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - /** - * @description The ID of the contact book - * @example clx1234567890 - */ - id: string; - /** - * @description The name of the contact book - * @example Newsletter Subscribers - */ - name: string; - /** - * @description The ID of the team - * @example 1 - */ - teamId: number; - /** - * @description Custom properties for the contact book - * @example { - * "customField1": "value1" - * } - */ - properties: { - [key: string]: string; - }; - /** - * @description The emoji associated with the contact book - * @example 📙 - */ - emoji: string; - /** @description The creation timestamp */ - createdAt: string; - /** @description The last update timestamp */ - updatedAt: string; - _count?: { - /** @description The number of contacts in the contact book */ - contacts?: number; - }; - }[]; - }; - }; - }; - }; - put?: never; - post: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - name: string; - emoji?: string; - properties?: { - [key: string]: string; - }; - }; - }; - }; - responses: { - /** @description Create a new contact book */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - id: string; - name: string; - teamId: number; - properties: { - [key: string]: string; - }; - emoji: string; - createdAt: string; - updatedAt: string; - }; - }; - }; - }; - }; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/v1/contactBooks/{contactBookId}": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get: { - parameters: { - query?: never; - header?: never; - path: { - contactBookId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Retrieve the contact book */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - id: string; - name: string; - teamId: number; - properties: { - [key: string]: string; - }; - emoji: string; - createdAt: string; - updatedAt: string; - _count?: { - contacts?: number; - }; - }; - }; - }; - /** @description Forbidden - API key doesn't have access */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error: string; - }; - }; - }; - /** @description Contact book not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error: string; - }; - }; - }; - }; - }; - put?: never; - post?: never; - delete: { - parameters: { - query?: never; - header?: never; - path: { - contactBookId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Contact book deleted successfully */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - id: string; - success: boolean; - message: string; - }; - }; - }; - /** @description Forbidden - API key doesn't have access */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error: string; - }; - }; - }; - /** @description Contact book not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error: string; - }; - }; - }; - }; - }; - options?: never; - head?: never; - patch: { - parameters: { - query?: never; - header?: never; - path: { - contactBookId: string; - }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - name?: string; - emoji?: string; - properties?: { - [key: string]: string; - }; - }; - }; - }; - responses: { - /** @description Update the contact book */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - id: string; - name: string; - teamId: number; - properties: { - [key: string]: string; - }; - emoji: string; - createdAt: string; - updatedAt: string; - }; - }; - }; - /** @description Forbidden - API key doesn't have access */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error: string; - }; - }; - }; - /** @description Contact book not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - error: string; - }; - }; - }; - }; - }; - trace?: never; - }; "/v1/contactBooks/{contactBookId}/contacts": { parameters: { query?: never; @@ -1112,88 +818,6 @@ export interface paths { patch?: never; trace?: never; }; - "/v1/contactBooks/{contactBookId}/contacts/bulk": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; - post: { - parameters: { - query?: never; - header?: never; - path: { - contactBookId: string; - }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - email: string; - firstName?: string; - lastName?: string; - properties?: { - [key: string]: string; - }; - subscribed?: boolean; - }[]; - }; - }; - responses: { - /** @description Bulk add contacts to a contact book */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - message: string; - count: number; - }; - }; - }; - }; - }; - delete: { - parameters: { - query?: never; - header?: never; - path: { - contactBookId: string; - }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - contactIds: string[]; - }; - }; - }; - responses: { - /** @description Bulk delete contacts from a contact book */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - success: boolean; - count: number; - }; - }; - }; - }; - }; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; "/v1/contactBooks/{contactBookId}/contacts/{contactId}": { parameters: { query?: never; @@ -1243,7 +867,6 @@ export interface paths { header?: never; path: { contactBookId: string; - contactId: string; }; cookie?: never; }; @@ -1340,6 +963,573 @@ export interface paths { }; trace?: never; }; + "/v1/contactBooks/{contactBookId}/contacts/bulk": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: { + parameters: { + query?: never; + header?: never; + path: { + contactBookId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + email: string; + firstName?: string; + lastName?: string; + properties?: { + [key: string]: string; + }; + subscribed?: boolean; + }[]; + }; + }; + responses: { + /** @description Bulk add contacts to a contact book */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + message: string; + count: number; + }; + }; + }; + }; + }; + delete: { + parameters: { + query?: never; + header?: never; + path: { + contactBookId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + contactIds: string[]; + }; + }; + }; + responses: { + /** @description Bulk delete contacts from a contact book */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + success: boolean; + count: number; + }; + }; + }; + }; + }; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/contactBooks": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Retrieve contact books accessible by the API key */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** + * @description The ID of the contact book + * @example clx1234567890 + */ + id: string; + /** + * @description The name of the contact book + * @example Newsletter Subscribers + */ + name: string; + /** + * @description The ID of the team + * @example 1 + */ + teamId: number; + /** + * @description Custom properties for the contact book + * @example { + * "customField1": "value1" + * } + */ + properties: { + [key: string]: string; + }; + /** + * @description Allowed personalization variables for contacts in this book + * @example [ + * "registrationCode", + * "company" + * ] + */ + variables: string[]; + /** + * @description The emoji associated with the contact book + * @example 📙 + */ + emoji: string; + /** + * @description Whether double opt-in is enabled for new contacts + * @example true + */ + doubleOptInEnabled?: boolean; + /** + * @description From address used for double opt-in emails (must use a verified domain) + * @example Newsletter + */ + doubleOptInFrom?: string | null; + /** + * @description Subject line used for double opt-in confirmation email + * @example Please confirm your subscription + */ + doubleOptInSubject?: string | null; + /** @description Email editor JSON content used for double opt-in confirmation */ + doubleOptInContent?: string | null; + /** @description The creation timestamp */ + createdAt: string; + /** @description The last update timestamp */ + updatedAt: string; + _count?: { + /** @description The number of contacts in the contact book */ + contacts: number; + }; + }[]; + }; + }; + }; + }; + put?: never; + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + name: string; + emoji?: string; + properties?: { + [key: string]: string; + }; + doubleOptInEnabled?: boolean; + doubleOptInFrom?: string | null; + doubleOptInSubject?: string; + doubleOptInContent?: string; + variables?: string[]; + }; + }; + }; + responses: { + /** @description Create a new contact book */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** + * @description The ID of the contact book + * @example clx1234567890 + */ + id: string; + /** + * @description The name of the contact book + * @example Newsletter Subscribers + */ + name: string; + /** + * @description The ID of the team + * @example 1 + */ + teamId: number; + /** + * @description Custom properties for the contact book + * @example { + * "customField1": "value1" + * } + */ + properties: { + [key: string]: string; + }; + /** + * @description Allowed personalization variables for contacts in this book + * @example [ + * "registrationCode", + * "company" + * ] + */ + variables: string[]; + /** + * @description The emoji associated with the contact book + * @example 📙 + */ + emoji: string; + /** + * @description Whether double opt-in is enabled for new contacts + * @example true + */ + doubleOptInEnabled?: boolean; + /** + * @description From address used for double opt-in emails (must use a verified domain) + * @example Newsletter + */ + doubleOptInFrom?: string | null; + /** + * @description Subject line used for double opt-in confirmation email + * @example Please confirm your subscription + */ + doubleOptInSubject?: string | null; + /** @description Email editor JSON content used for double opt-in confirmation */ + doubleOptInContent?: string | null; + /** @description The creation timestamp */ + createdAt: string; + /** @description The last update timestamp */ + updatedAt: string; + _count?: { + /** @description The number of contacts in the contact book */ + contacts: number; + }; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/contactBooks/{contactBookId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: { + parameters: { + query?: never; + header?: never; + path: { + contactBookId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Retrieve the contact book */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** + * @description The ID of the contact book + * @example clx1234567890 + */ + id: string; + /** + * @description The name of the contact book + * @example Newsletter Subscribers + */ + name: string; + /** + * @description The ID of the team + * @example 1 + */ + teamId: number; + /** + * @description Custom properties for the contact book + * @example { + * "customField1": "value1" + * } + */ + properties: { + [key: string]: string; + }; + /** + * @description Allowed personalization variables for contacts in this book + * @example [ + * "registrationCode", + * "company" + * ] + */ + variables: string[]; + /** + * @description The emoji associated with the contact book + * @example 📙 + */ + emoji: string; + /** + * @description Whether double opt-in is enabled for new contacts + * @example true + */ + doubleOptInEnabled?: boolean; + /** + * @description From address used for double opt-in emails (must use a verified domain) + * @example Newsletter + */ + doubleOptInFrom?: string | null; + /** + * @description Subject line used for double opt-in confirmation email + * @example Please confirm your subscription + */ + doubleOptInSubject?: string | null; + /** @description Email editor JSON content used for double opt-in confirmation */ + doubleOptInContent?: string | null; + /** @description The creation timestamp */ + createdAt: string; + /** @description The last update timestamp */ + updatedAt: string; + _count?: { + /** @description The number of contacts in the contact book */ + contacts: number; + }; + }; + }; + }; + /** @description Forbidden - API key doesn't have access to this contact book */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error: string; + }; + }; + }; + /** @description Contact book not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error: string; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete: { + parameters: { + query?: never; + header?: never; + path: { + contactBookId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Contact book deleted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + id: string; + success: boolean; + message: string; + }; + }; + }; + /** @description Forbidden - API key doesn't have access */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error: string; + }; + }; + }; + /** @description Contact book not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error: string; + }; + }; + }; + }; + }; + options?: never; + head?: never; + patch: { + parameters: { + query?: never; + header?: never; + path: { + contactBookId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + name?: string; + emoji?: string; + properties?: { + [key: string]: string; + }; + doubleOptInEnabled?: boolean; + doubleOptInFrom?: string | null; + doubleOptInSubject?: string; + doubleOptInContent?: string; + variables?: string[]; + }; + }; + }; + responses: { + /** @description Update the contact book */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** + * @description The ID of the contact book + * @example clx1234567890 + */ + id: string; + /** + * @description The name of the contact book + * @example Newsletter Subscribers + */ + name: string; + /** + * @description The ID of the team + * @example 1 + */ + teamId: number; + /** + * @description Custom properties for the contact book + * @example { + * "customField1": "value1" + * } + */ + properties: { + [key: string]: string; + }; + /** + * @description Allowed personalization variables for contacts in this book + * @example [ + * "registrationCode", + * "company" + * ] + */ + variables: string[]; + /** + * @description The emoji associated with the contact book + * @example 📙 + */ + emoji: string; + /** + * @description Whether double opt-in is enabled for new contacts + * @example true + */ + doubleOptInEnabled?: boolean; + /** + * @description From address used for double opt-in emails (must use a verified domain) + * @example Newsletter + */ + doubleOptInFrom?: string | null; + /** + * @description Subject line used for double opt-in confirmation email + * @example Please confirm your subscription + */ + doubleOptInSubject?: string | null; + /** @description Email editor JSON content used for double opt-in confirmation */ + doubleOptInContent?: string | null; + /** @description The creation timestamp */ + createdAt: string; + /** @description The last update timestamp */ + updatedAt: string; + _count?: { + /** @description The number of contacts in the contact book */ + contacts: number; + }; + }; + }; + }; + /** @description Forbidden - API key doesn't have access to this contact book */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error: string; + }; + }; + }; + /** @description Contact book not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + error: string; + }; + }; + }; + }; + }; + trace?: never; + }; "/v1/campaigns": { parameters: { query?: never; @@ -1350,11 +1540,8 @@ export interface paths { get: { parameters: { query?: { - /** @description Page number for pagination (default: 1) */ page?: string; - /** @description Filter campaigns by status */ status?: "DRAFT" | "SCHEDULED" | "RUNNING" | "PAUSED" | "SENT"; - /** @description Search campaigns by name or subject */ search?: string; }; header?: never; @@ -1379,8 +1566,7 @@ export interface paths { createdAt: string; /** Format: date-time */ updatedAt: string; - /** @enum {string} */ - status: "DRAFT" | "SCHEDULED" | "RUNNING" | "PAUSED" | "SENT"; + status: string; /** Format: date-time */ scheduledAt: string | null; total: number; @@ -1474,9 +1660,7 @@ export interface paths { parameters: { query?: never; header?: never; - path: { - campaignId: string; - }; + path?: never; cookie?: never; }; get: { @@ -1725,9 +1909,7 @@ export interface paths { get: { parameters: { query?: { - /** @description Number of days to retrieve data for (default: 30) */ days?: "7" | "30"; - /** @description Filter by domain ID */ domainId?: string; }; header?: never; @@ -1783,7 +1965,6 @@ export interface paths { get: { parameters: { query?: { - /** @description Filter by domain ID */ domainId?: string; }; header?: never;