{ "openapi": "3.1.0", "info": { "title": "Warmbly API", "version": "1.0.0", "description": "The Warmbly API lets you drive mailboxes, campaigns, contacts, the unibox, CRM, and more programmatically. Authenticate with an API key as a Bearer token. All paths are relative to the versioned base URL.", "contact": { "name": "Warmbly", "url": "https://docs.warmbly.com" }, "license": { "name": "Proprietary", "url": "https://warmbly.com" } }, "servers": [ { "url": "https://api.warmbly.com/v1", "description": "Production (v1)" } ], "security": [ { "bearerAuth": [] } ], "tags": [ { "name": "auth", "description": "Authentication: login, registration, password reset, 2FA, and sessions." }, { "name": "mailboxes", "description": "Connected sending mailboxes and their warmup lifecycle." }, { "name": "campaigns", "description": "Cold outreach campaigns, steps, and A/B variants." }, { "name": "contacts", "description": "Contacts and their tags." }, { "name": "unibox", "description": "Unified inbox: threads, replies, and labels." }, { "name": "crm", "description": "Deals, tasks, notes, and pipelines." }, { "name": "api-keys", "description": "API key management and usage logs." }, { "name": "webhooks", "description": "Outbound webhook endpoints and deliveries." }, { "name": "analytics", "description": "Campaign and deliverability analytics." }, { "name": "placement", "description": "Inbox placement tests, seed inboxes and campaign placement monitors." }, { "name": "integrations", "description": "Third-party connections and automations." }, { "name": "account-org", "description": "Account, organization, and plan reference data." }, { "name": "deliverability-ops", "description": "Deliverability event ingest, suppression, and seed placement." }, { "name": "ai", "description": "The AI tool registry over REST, for function-calling agents that do not speak MCP." } ], "paths": { "/auth/login": { "post": { "operationId": "auth_login_start", "summary": "Start login (request email code)", "description": "Step 1 of email login. Verifies the email/password and Turnstile token, then emails a one-time confirmation code. Returns an opaque session handle to pass to /auth/login/confirm.", "tags": [ "auth" ], "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthCredentials" } } } }, "responses": { "200": { "description": "Confirmation code sent; returns the session handle.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthSession" } } } }, "400": { "description": "Invalid request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Turnstile / captcha rejected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/login/confirm": { "post": { "operationId": "auth_login_confirm", "summary": "Confirm login (exchange code for tokens)", "description": "Step 2 of email login. Exchanges the session handle plus the emailed code for a token pair. If 2FA is enabled, returns a 2FA challenge (pending_token) instead of a session.", "tags": [ "auth" ], "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfirmRequest" } } } }, "responses": { "200": { "description": "Login result: either a full token pair, or a 2FA challenge.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LoginResult" } } } }, "400": { "description": "Invalid request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Wrong or expired code, or invalid session.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Turnstile / captcha rejected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited / too many attempts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/register": { "post": { "operationId": "auth_register_start", "summary": "Start registration (request email code)", "description": "Step 1 of registration. Validates email/password and Turnstile, then emails a confirmation code. Returns an opaque session handle for /auth/register/confirm.", "tags": [ "auth" ], "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthCredentials" } } } }, "responses": { "200": { "description": "Confirmation code sent; returns the session handle.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthSession" } } } }, "400": { "description": "Invalid request body or weak password.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Email already in use or not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Turnstile / captcha rejected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/register/confirm": { "post": { "operationId": "auth_register_confirm", "summary": "Confirm registration", "description": "Step 2 of registration. Exchanges the session handle plus the emailed code to finalize the account. Returns 204 on success.", "tags": [ "auth" ], "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfirmRequest" } } } }, "responses": { "204": { "description": "Account confirmed." }, "400": { "description": "Invalid request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Wrong or expired code, or invalid session.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Turnstile / captcha rejected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/refresh": { "post": { "operationId": "auth_refresh", "summary": "Refresh the token pair", "description": "Exchanges a valid refresh token for a new token pair (rotating refresh).", "tags": [ "auth" ], "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RefreshRequest" } } } }, "responses": { "200": { "description": "A fresh token pair.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TokenPair" } } } }, "400": { "description": "Invalid request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Refresh token invalid, expired, or revoked.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/reset-password": { "post": { "operationId": "auth_reset_password_start", "summary": "Start password reset", "description": "Sends a password-reset code to the email if an account exists. Always returns 200 to avoid account enumeration.", "tags": [ "auth" ], "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResetPasswordStartRequest" } } } }, "responses": { "200": { "description": "Reset email sent if the account exists." }, "400": { "description": "Invalid request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Turnstile / captcha rejected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/reset-password/confirm": { "post": { "operationId": "auth_reset_password_confirm", "summary": "Confirm password reset", "description": "Exchanges the reset session handle plus a new password to set a new password.", "tags": [ "auth" ], "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResetPasswordConfirmRequest" } } } }, "responses": { "200": { "description": "Password updated." }, "400": { "description": "Invalid request body or weak password.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Invalid or expired reset session.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Turnstile / captcha rejected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/2fa/verify": { "post": { "operationId": "auth_2fa_verify_login", "summary": "Verify 2FA login challenge", "description": "Exchanges the single-use pending_token from /auth/login/confirm plus a TOTP or recovery code for a real token pair.", "tags": [ "auth" ], "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TwoFAVerifyRequest" } } } }, "responses": { "200": { "description": "A full token pair.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TokenPair" } } } }, "400": { "description": "Invalid request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Pending token invalid/expired, or code wrong.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Too many attempts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/sso/link": { "post": { "operationId": "auth_sso_link", "summary": "Link a provider sign-in to an existing password account", "description": "Completes a Google, Apple or OpenID Connect sign-in that came back link_required: the provider's verified address already belongs to an account with a password. A correct password attaches the provider identity to that account and returns the session, or a 2FA challenge when the account has TOTP enrolled (the identity is then attached once /auth/2fa/verify passes). A wrong password is refused like a sign-in and counts against the same per-address budget; three wrong answers, or ten minutes, end the challenge with the code sso_link_expired and the sign-in has to be started again.", "tags": [ "auth" ], "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SSOLinkRequest" } } } }, "responses": { "200": { "description": "The session, or a 2FA challenge.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LoginResult" } } } }, "400": { "description": "Invalid request body, wrong password (Invalid email or password.), or an unknown, expired, used or exhausted pending token (code sso_link_expired).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account or the identity can no longer be linked: the account is suspended, already holds a different identity from this provider, or the identity belongs to another account.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/passkey/login/begin": { "post": { "operationId": "auth_passkey_login_begin", "summary": "Begin passkey (WebAuthn) login", "description": "Starts a discoverable/usernameless passkey login. Returns the WebAuthn assertion options plus an opaque session handle to pass to /auth/passkey/login/finish.", "tags": [ "auth" ], "security": [], "responses": { "200": { "description": "WebAuthn assertion options and the login session handle.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PasskeyLoginChallenge" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/passkey/login/finish": { "post": { "operationId": "auth_passkey_login_finish", "summary": "Finish passkey (WebAuthn) login", "description": "Submits the WebAuthn assertion together with the login session handle. On success returns a full token pair.", "tags": [ "auth" ], "security": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PasskeyLoginFinishRequest" } } } }, "responses": { "200": { "description": "A full token pair.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TokenPair" } } } }, "400": { "description": "Invalid request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Assertion rejected or session invalid.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/logout": { "post": { "operationId": "auth_logout", "summary": "Log out the current session", "description": "Revokes the session bound to the bearer access token. Requires a user session token (not an API key).", "tags": [ "auth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Session revoked." }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/logout-all": { "post": { "operationId": "auth_logout_all", "summary": "Log out all sessions", "description": "Revokes every active session for the authenticated user. Requires a user session token (not an API key).", "tags": [ "auth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "All sessions revoked." }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/me": { "get": { "operationId": "auth_get_me", "summary": "Get the authenticated user", "description": "Returns the current user profile, including per-user folders, tags, and categories. Requires a user session token (not an API key).", "tags": [ "auth" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The authenticated user.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "auth_update_me", "summary": "Update the authenticated user's profile", "description": "Updates basic profile fields for the current user. Requires a user session token (not an API key).", "tags": [ "auth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateProfileRequest" } } } }, "responses": { "200": { "description": "The updated user.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } }, "400": { "description": "Invalid request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/me/password": { "post": { "operationId": "auth_change_password", "summary": "Change password", "description": "Changes the signed-in user's password (current + new). Every session the account holds is ended, the calling one included, and the response is the token pair of a new session for the calling device; tokens issued before the change are refused after it. Requires a user session token (not an API key).", "tags": [ "auth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChangePasswordRequest" } } } }, "responses": { "200": { "description": "Password changed. The body is the token pair of the new session; every earlier token is now refused.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TokenPair" } } } }, "400": { "description": "Invalid request body or weak new password.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Current password wrong or session invalid.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "The new password is stored but the calling device could not be issued a new session (code `password_changed_sign_in_again`). Discard the old tokens and sign in again.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/sessions": { "get": { "operationId": "auth_list_sessions", "summary": "List active sessions", "description": "Lists the authenticated user's active sessions, with the caller's current session flagged. Requires a user session token (not an API key). This endpoint returns a plain array, not a paginated wrapper.", "tags": [ "auth" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Active sessions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionList" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "auth_revoke_other_sessions", "summary": "Revoke all other sessions", "description": "Ends every active session except the current one. Requires a user session token (not an API key).", "tags": [ "auth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Other sessions revoked." }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/sessions/{id}": { "delete": { "operationId": "auth_revoke_session", "summary": "Revoke a specific session", "description": "Ends one of the user's sessions by id. Requires a user session token (not an API key).", "tags": [ "auth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Session id to revoke." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Session revoked." }, "400": { "description": "Invalid session id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Session not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/2fa/status": { "get": { "operationId": "auth_2fa_status", "summary": "Get 2FA status", "description": "Reports whether the authenticated user has 2FA enabled. Requires a user session token (not an API key).", "tags": [ "auth" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "2FA status.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TwoFAStatus" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/2fa/enroll/start": { "post": { "operationId": "auth_2fa_enroll_start", "summary": "Begin 2FA enrollment", "description": "Generates a fresh TOTP secret and otpauth provisioning URI (shown once). Requires a user session token (not an API key).", "tags": [ "auth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "The TOTP secret and otpauth URI.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TwoFAEnrollStart" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/2fa/enroll/confirm": { "post": { "operationId": "auth_2fa_enroll_confirm", "summary": "Confirm 2FA enrollment", "description": "Verifies a TOTP code, enables 2FA, and returns one-time recovery codes (shown once). Requires a user session token (not an API key).", "tags": [ "auth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TwoFACodeRequest" } } } }, "responses": { "200": { "description": "Recovery codes.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TwoFARecoveryCodes" } } } }, "400": { "description": "Invalid request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Wrong code or session invalid.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/2fa/recovery-codes": { "post": { "operationId": "auth_2fa_regenerate_recovery_codes", "summary": "Regenerate recovery codes", "description": "Replaces every recovery code with a fresh set, returned once. Requires a current TOTP or recovery code in the body; a mismatch answers 400 with code two_fa_invalid_code. Requires a user session token (not an API key). Idempotency-Key is not needed: the proof code is single-use, so a retried request is refused rather than rotating the set twice. Wrong codes share the per-account attempt budget with /auth/reauth.", "tags": [ "auth" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TwoFACodeRequest" } } } }, "responses": { "200": { "description": "The new recovery codes.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TwoFARecoveryCodes" } } } }, "400": { "description": "Invalid request body, 2FA not enabled, or the code did not match (two_fa_invalid_code).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/2fa": { "delete": { "operationId": "auth_2fa_disable", "summary": "Disable 2FA", "description": "Turns off 2FA for the user. Requires a current TOTP or recovery code in the body. Requires a user session token (not an API key).", "tags": [ "auth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TwoFACodeRequest" } } } }, "responses": { "200": { "description": "2FA disabled.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } } }, "400": { "description": "Invalid request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Wrong code or session invalid.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/passkey/credentials": { "get": { "operationId": "auth_list_passkey_credentials", "summary": "List passkey credentials", "description": "Lists the authenticated user's registered passkeys. Requires a user session token (not an API key). Returns a plain array, not a paginated wrapper.", "tags": [ "auth" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Registered passkeys.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PasskeyCredentialList" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/passkey/credentials/{id}": { "patch": { "operationId": "auth_rename_passkey_credential", "summary": "Rename a passkey", "description": "Renames a registered passkey by id. Requires a user session token (not an API key).", "tags": [ "auth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Passkey credential id." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PasskeyRenameRequest" } } } }, "responses": { "200": { "description": "The updated passkey.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PasskeyCredential" } } } }, "400": { "description": "Invalid request body or id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Passkey not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "auth_delete_passkey_credential", "summary": "Delete a passkey", "description": "Removes a registered passkey by id. Requires a user session token (not an API key).", "tags": [ "auth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Passkey credential id." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Passkey deleted." }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Not allowed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Passkey not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails": { "get": { "operationId": "mailboxes_list", "summary": "List mailboxes", "description": "Returns the organization's connected mailboxes, newest first, with cursor pagination.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "q", "in": "query", "required": false, "description": "Free-text search over mailbox address and name.", "schema": { "type": "string" } }, { "name": "tag", "in": "query", "required": false, "description": "Tag id to filter by.", "schema": { "type": "string", "format": "uuid" } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque pagination token from a previous pagination.next_cursor.", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "required": false, "description": "Page size. Default 50, max 100.", "schema": { "type": "integer", "default": 50, "maximum": 100, "minimum": 1 } } ], "responses": { "200": { "description": "A page of mailboxes.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxList" } } } }, "400": { "description": "Invalid cursor, limit, or tag.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/{id}": { "get": { "operationId": "mailboxes_get", "summary": "Get a mailbox", "description": "Returns a single mailbox by id.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The mailbox (email account) id.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The mailbox.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Mailbox" } } } }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope, permission, or mailbox not allowed for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "mailboxes_update", "summary": "Update a mailbox", "description": "Updates mailbox settings. All fields are optional; only present fields are applied.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" }, { "name": "id", "in": "path", "required": true, "description": "The mailbox id.", "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxUpdate" } } } }, "responses": { "200": { "description": "The updated mailbox.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Mailbox" } } } }, "400": { "description": "Invalid request body or id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope, permission, or mailbox not allowed for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "mailboxes_delete", "summary": "Delete a mailbox", "description": "Disconnects and deletes a mailbox. It is removed from all warmup pools, and everything belonging to it goes with it: imported mail, warmup history, credentials, sender links and any scheduled send.\n\nTwo parts of the erasure finish just after the response, because neither can be done in the instant the record goes. A Gmail mailbox's OAuth grant is handed back to Google, which invalidates its tokens and removes the app from the customer's third-party access list; Microsoft publishes no per-application revocation endpoint, so an Outlook mailbox's tokens are destroyed locally and the customer removes the app at their Microsoft account. The message bodies stored outside the database are deleted. Both are retried until they succeed.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" }, { "name": "id", "in": "path", "required": true, "description": "The mailbox id.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "204": { "description": "Mailbox deleted." }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope, permission, or mailbox not allowed for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/{id}/track": { "patch": { "operationId": "mailboxes_update_tracking_domain", "summary": "Update the tracking domain", "description": "Sets or clears the custom open/click tracking domain for a mailbox. Send an empty domain to clear it and fall back to the shared default.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" }, { "name": "id", "in": "path", "required": true, "description": "The mailbox id.", "schema": { "type": "string", "format": "uuid" } }, { "name": "domain", "in": "query", "required": false, "description": "The custom tracking subdomain (for example t.acme.com). Empty clears it.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "The resolved tracking-domain state.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxTrackingDomain" } } } }, "400": { "description": "Invalid id or domain.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope, permission, or mailbox not allowed for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/{id}/warmup/start": { "post": { "operationId": "mailboxes_warmup_start", "summary": "Start warmup", "description": "Enables warmup for a mailbox. When resuming from a paused state it preserves ramp progress.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" }, { "name": "id", "in": "path", "required": true, "description": "The mailbox id.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The updated mailbox.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Mailbox" } } } }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope, permission, or mailbox not allowed for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/{id}/warmup/pause": { "post": { "operationId": "mailboxes_warmup_pause", "summary": "Pause warmup", "description": "Pauses warmup without losing ramp progress. A later start continues from the same daily volume.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" }, { "name": "id", "in": "path", "required": true, "description": "The mailbox id.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The updated mailbox. A paused mailbox has a non-null warmup_paused_at.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Mailbox" } } } }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope, permission, or mailbox not allowed for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/{id}/warmup/resume": { "post": { "operationId": "mailboxes_warmup_resume", "summary": "Resume warmup", "description": "Resumes a paused warmup, shifting the ramp anchor forward so progress continues where it left off.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" }, { "name": "id", "in": "path", "required": true, "description": "The mailbox id.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The updated mailbox, with warmup_paused_at cleared.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Mailbox" } } } }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope, permission, or mailbox not allowed for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/{id}/warmup/stop": { "post": { "operationId": "mailboxes_warmup_stop", "summary": "Stop warmup", "description": "Disables warmup entirely and clears ramp progress. A later start begins a fresh ramp.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" }, { "name": "id", "in": "path", "required": true, "description": "The mailbox id.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The updated mailbox, with warmup disabled.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Mailbox" } } } }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope, permission, or mailbox not allowed for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/{id}/auth-check": { "get": { "operationId": "mailboxes_auth_check", "summary": "Check domain authentication", "description": "Validates SPF, DKIM, and DMARC for the mailbox's sending domain on demand.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The mailbox id. The domain is derived from the mailbox address.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The authentication-check result.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxAuthCheck" } } } }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope, permission, or mailbox not allowed for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/{id}/sync": { "get": { "operationId": "mailboxes_sync_state", "summary": "Get sync state", "description": "Where the mailbox's initial import stands, whether fair use is holding new mail, the budget the mailbox syncs under, the folders its sync leaves alone, and the folders the worker has seen on the server. `state` is null until the worker has reported once.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The mailbox id.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The mailbox's sync state and policy.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxSync" } } } }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope, permission, or mailbox not allowed for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "put": { "operationId": "mailboxes_sync_update", "summary": "Set skipped folders", "description": "Replaces the folders an IMAP mailbox's sync leaves alone. Names are matched as the mail server lists them, without regard to case, and each covers its subfolders. Mail already stored from a newly skipped folder is removed from Warmbly (never from the mailbox), and the mailbox is re-shipped to its worker so the change applies on the next pass. The body is the desired state, so the call is naturally idempotent. INBOX and the sent, drafts, spam, trash and archive folders cannot be skipped.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The mailbox id.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The skip list as stored.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxSyncSettings" } } } }, "400": { "description": "Invalid id or body, or `invalid_sync_folder`: a folder the sync always follows, a malformed or over-long name, more than 50 names, or a mailbox that is not IMAP.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope, permission, or mailbox not allowed for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxSyncSettings" } } } } } }, "/emails/{id}/identity": { "get": { "operationId": "mailboxes_send_identity", "summary": "Get the sending identity", "description": "Which addresses the mailbox's provider will let it send as, which one it uses, and where its stored signature came from. Stored state only: the provider is not contacted.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The mailbox id.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The mailbox's sending identity.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxSendIdentity" } } } }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope, permission, or mailbox not allowed for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/{id}/identity/refresh": { "post": { "operationId": "mailboxes_refresh_send_identity", "summary": "Refresh the sending identity", "description": "Re-reads the send-as addresses from the provider and stores them, optionally importing the provider's signature. The read runs on the worker holding the mailbox, never from the API itself, so the provider keeps seeing the mailbox from one address. A send-as choice the provider no longer verifies is cleared by the same call. Gmail only. Retry-safe without an Idempotency-Key: it stores exactly what the provider currently reports.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The mailbox id.", "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxSendIdentityRefreshRequest" } } } }, "responses": { "200": { "description": "The refreshed sending identity.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxSendIdentity" } } } }, "400": { "description": "Invalid id, a provider with no send-as list (mailbox_send_as_unsupported), or a signature larger than Warmbly stores (mailbox_signature_too_large).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope, permission, or mailbox not allowed for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "The mailbox is not running on a worker right now (mailbox_identity_unavailable); nothing was changed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/verify": { "post": { "operationId": "mailboxes_verify_address", "summary": "Verify an email address", "description": "Verifies a single email address on demand (syntax, MX, SMTP RCPT probe, catch-all detection). The address may be supplied in the JSON body or as the email query param; the body takes precedence.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" }, { "name": "email", "in": "query", "required": false, "description": "The address to verify. Used when not supplied in the body.", "schema": { "type": "string" } } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxVerifyRequest" } } } }, "responses": { "200": { "description": "The verification result.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxVerifyResult" } } } }, "400": { "description": "Missing or empty address.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/{id}/warmup/ban-status": { "get": { "operationId": "mailboxes_warmup_ban_status", "summary": "Get warmup ban status", "description": "Returns whether a mailbox is blocked from the shared warmup pool, why, and whether the owner can appeal.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The mailbox id.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The warmup ban status.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxWarmupBanStatus" } } } }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope, permission, or mailbox not allowed for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/{id}/warmup/appeal": { "post": { "operationId": "mailboxes_warmup_appeal", "summary": "Submit a warmup appeal", "description": "Lets the mailbox owner appeal a warmup ban with a reason.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" }, { "name": "id", "in": "path", "required": true, "description": "The mailbox id.", "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxWarmupAppealRequest" } } } }, "responses": { "200": { "description": "The created appeal id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxWarmupAppealResult" } } } }, "400": { "description": "Invalid id or request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope, permission, or mailbox not allowed for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/{id}/send": { "post": { "operationId": "mailboxes_send", "summary": "Send from a mailbox", "description": "Sends a one-off email from a specific mailbox, scheduled and dispatched through the mailbox's assigned worker. Requires an active organization.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" }, { "name": "id", "in": "path", "required": true, "description": "The sending mailbox id.", "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxSendRequest" } } } }, "responses": { "200": { "description": "The queued send task.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxSendResult" } } } }, "400": { "description": "Invalid id, request body, or no active organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope, permission, or mailbox not allowed for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns": { "get": { "operationId": "campaigns_list", "summary": "List campaigns", "description": "Search and page through the organization's campaigns. Scope READ_CAMPAIGNS, org permission view_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "q", "in": "query", "required": false, "description": "Free-text filter on campaign name.", "schema": { "type": "string" } }, { "name": "folder", "in": "query", "required": false, "description": "Restrict to a single folder id.", "schema": { "type": "string" } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque pagination cursor from the previous page.", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "required": false, "description": "Page size (default 50, max 100).", "schema": { "type": "integer", "default": 50, "maximum": 100, "minimum": 1 } } ], "responses": { "200": { "description": "A page of campaigns.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignList" } } } }, "400": { "description": "Invalid cursor or limit.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "campaigns_create", "summary": "Create a campaign", "description": "Create a campaign. Only name is required. Scope WRITE_CAMPAIGNS, org permission manage_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignCreate" } } } }, "responses": { "201": { "description": "The created campaign.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Campaign" } } } }, "400": { "description": "Validation error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}": { "get": { "operationId": "campaigns_get", "summary": "Get a campaign", "description": "Fetch a single campaign by id. Scope READ_CAMPAIGNS, org permission view_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The campaign.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Campaign" } } } }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "campaigns_update", "summary": "Update a campaign", "description": "Patch any subset of campaign fields. Omitted fields are unchanged. Scope WRITE_CAMPAIGNS, org permission manage_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignUpdate" } } } }, "responses": { "200": { "description": "The updated campaign.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Campaign" } } } }, "400": { "description": "Validation error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "campaigns_delete", "summary": "Delete a campaign", "description": "Permanently delete a campaign. Scope WRITE_CAMPAIGNS, org permission manage_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Deleted." }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/advanced": { "get": { "operationId": "campaigns_get_advanced", "summary": "Get advanced settings", "description": "Return the campaign's advanced outreach overrides. Scope READ_CAMPAIGNS, org permission view_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The advanced settings.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignAdvancedSettings" } } } }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "campaigns_update_advanced", "summary": "Update advanced settings", "description": "Replace the campaign's advanced overrides. Scope WRITE_CAMPAIGNS, org permission manage_settings.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignAdvancedUpdate" } } } }, "responses": { "204": { "description": "Updated." }, "400": { "description": "Validation error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/ab-variants": { "get": { "operationId": "campaigns_list_ab_variants", "summary": "List A/B variants", "description": "List the campaign's A/B variants. Scope READ_CAMPAIGNS, org permission view_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The variants.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignABVariantList" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "campaigns_create_ab_variant", "summary": "Create an A/B variant", "description": "Add a variant to the campaign (or one step via step_id). Scope WRITE_CAMPAIGNS, org permission manage_settings.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignABVariantCreate" } } } }, "responses": { "201": { "description": "The created variant.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignABVariant" } } } }, "400": { "description": "Validation error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/ab-variants/{variantId}": { "patch": { "operationId": "campaigns_update_ab_variant", "summary": "Update an A/B variant", "description": "Patch a variant. Omitted fields are unchanged. Scope WRITE_CAMPAIGNS, org permission manage_settings.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "variantId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignABVariantUpdate" } } } }, "responses": { "200": { "description": "The updated variant.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignABVariant" } } } }, "400": { "description": "Validation error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "campaigns_delete_ab_variant", "summary": "Delete an A/B variant", "description": "Remove a variant. Scope WRITE_CAMPAIGNS, org permission manage_settings.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "variantId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Deleted." }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/ab-analysis": { "get": { "operationId": "campaigns_get_ab_analysis", "summary": "Get A/B analysis", "description": "Return per-variant engagement stats and the computed winner. Scope READ_ANALYTICS, org permission view_analytics.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The A/B analysis.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ABWinnerAnalysis" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/attachments": { "get": { "operationId": "campaigns_list_attachments", "summary": "List attachments", "description": "List the campaign's attachments, each with a short-lived presigned download url. Scope READ_CAMPAIGNS, org permission view_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The attachments.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignAttachmentList" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "campaigns_upload_attachment", "summary": "Upload an attachment", "description": "Upload a file (max 15 MB) to attach to the campaign or one step. Multipart form data. Scope WRITE_CAMPAIGNS, org permission manage_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "required": [ "file" ], "properties": { "file": { "type": "string", "format": "binary", "description": "The file to upload (max 15 MB). Executable and script types are rejected." }, "step_id": { "type": "string", "format": "uuid", "description": "Scope the attachment to one sequence step of this campaign, which is then the only step that sends it. Omit to attach the file to every step. A step of another campaign is 404." } } } } } }, "responses": { "201": { "description": "The created attachment.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignAttachment" } } } }, "400": { "description": "Validation error or rejected file type.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/attachments/{attachmentId}": { "delete": { "operationId": "campaigns_delete_attachment", "summary": "Delete an attachment", "description": "Delete a campaign attachment and its stored object. Scope WRITE_CAMPAIGNS, org permission manage_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "attachmentId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Deleted." }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/preflight": { "post": { "operationId": "campaigns_run_preflight", "summary": "Run preflight", "description": "Run the campaign's preflight validation checks and return a scored report. No mail is sent. Scope SEND_CAMPAIGNS, org permission send_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "The preflight report.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PreflightReport" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/test-email": { "post": { "operationId": "campaigns_send_test_email", "summary": "Send a test email", "description": "Send a one-off preview of a sequence step to a recipient through a chosen mailbox. Scope SEND_CAMPAIGNS, org permission send_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignTestEmailRequest" } } } }, "responses": { "200": { "description": "Test email sent.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignTestEmailResult" } } } }, "400": { "description": "Validation error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/placement-monitor": { "get": { "operationId": "campaigns_placement_monitor_get", "tags": [ "campaigns", "placement" ], "summary": "Get a campaign's placement monitor", "description": "The campaign's scheduled placement test, or null when it has none. Scope READ_CAMPAIGNS, org permission view_campaigns.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Campaign id.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The monitor, or null.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "oneOf": [ { "$ref": "#/components/schemas/PlacementMonitor" }, { "type": "null" } ] } } } } } }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "The campaign is not in the workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "put": { "operationId": "campaigns_placement_monitor_put", "tags": [ "campaigns", "placement" ], "summary": "Set a campaign's placement monitor", "description": "Create or update the campaign's monitor, which re-tests its first email step on a schedule while it is active, rotating through its sending mailboxes. Absent fields keep their value, or the default on a new monitor. A new or re-enabled monitor runs within about five minutes. The body states values, so a retry lands on the same state. Scope SEND_CAMPAIGNS, org permission send_campaigns.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Campaign id.", "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlacementMonitorRequest" } } } }, "responses": { "200": { "description": "The monitor.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PlacementMonitor" } } } } } }, "400": { "description": "Invalid body, interval_days outside 1 to 30, alert_below outside 0 to 100, or an unknown panel.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "The campaign is not in the workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "campaigns_placement_monitor_delete", "tags": [ "campaigns", "placement" ], "summary": "Remove a campaign's placement monitor", "description": "Remove the campaign's monitor. Tests it already ran stay. Scope SEND_CAMPAIGNS, org permission send_campaigns.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Campaign id.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "204": { "description": "Removed." }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "The campaign is not in the workspace, or it has no monitor.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/start": { "post": { "operationId": "campaigns_start", "summary": "Start a campaign", "description": "Activate the campaign so it begins sending real mail. Scope SEND_CAMPAIGNS, org permission send_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "Started.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignStartResult" } } } }, "400": { "description": "Campaign not in a startable state.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/stop": { "post": { "operationId": "campaigns_stop", "summary": "Stop a campaign", "description": "Pause an active campaign. Scope SEND_CAMPAIGNS, org permission send_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "Stopped.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignStopResult" } } } }, "400": { "description": "Campaign not in a stoppable state.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/leads/{contactId}/hold": { "get": { "operationId": "campaigns_get_lead_hold", "summary": "Get a lead's hold", "description": "Read whether one contact's flow inside this campaign is currently held. Scope READ_CAMPAIGNS, org permission view_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "contactId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "OK.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignLeadHoldResult" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "The campaign is not the caller's organization's, or the contact is not a lead of it.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/leads/{contactId}/pause": { "post": { "operationId": "campaigns_pause_lead", "summary": "Pause a lead", "description": "Hold one contact's flow inside one campaign until a date, or with no end. The contact stays subscribed and stays a lead. The body states an absolute hold rather than a delta, so a retry lands on the same state. Scope WRITE_CAMPAIGNS, org permission manage_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "contactId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignLeadPauseRequest" } } } }, "responses": { "200": { "description": "OK.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignLeadHoldResult" } } } }, "400": { "description": "until is in the past, or more than a year away.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "The campaign is not the caller's organization's, or the contact is not a lead of it.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/leads/{contactId}/resume": { "post": { "operationId": "campaigns_resume_lead", "summary": "Resume a lead", "description": "Lift the hold now. The held time is dropped rather than carried, and the campaign's wakeup is pulled forward. Resuming a lead that is not held succeeds and changes nothing. Scope WRITE_CAMPAIGNS, org permission manage_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "contactId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "OK.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignLeadHoldResult" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "The campaign is not the caller's organization's, or the contact is not a lead of it.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/leads/{contactId}/cc": { "get": { "operationId": "campaigns_get_lead_cc", "summary": "Get a lead's CC", "description": "List the contacts copied on every email this campaign sends one lead. Scope READ_CAMPAIGNS and READ_CONTACTS, org permission view_campaigns and view_contacts.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "contactId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "OK.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignLeadCCResult" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "The campaign is not the caller's organization's, or the contact is not a lead of it.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "put": { "operationId": "campaigns_set_lead_cc", "summary": "Set a lead's CC", "description": "Replace the contacts copied on every email this campaign sends one lead, follow-ups included. An empty list removes them all. A copied contact who is also a lead of the campaign has their own sequence held (source cc) while any lead copies them. The body is the whole list, so retries are safe without an Idempotency-Key. Scope WRITE_CAMPAIGNS and READ_CONTACTS, org permission manage_campaigns and view_contacts.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "contactId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignLeadCCRequest" } } } }, "responses": { "200": { "description": "OK.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignLeadCCResult" } } } }, "400": { "description": "bad_request: a contact_ids entry is not a uuid; lead_cc_limit: more than 2 contacts; lead_cc_self: the lead is in its own list.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "not_found: the campaign is not the caller's organization's, or the contact is not a lead of it; lead_cc_contact_not_found: a contact to copy is not in the workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "lead_cc_lead_is_copied: the lead is copied on another lead in this campaign; lead_cc_has_copies: a contact to copy has copies of their own in this campaign.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/leads/{contactId}/cc/suggestions": { "get": { "operationId": "campaigns_suggest_lead_cc", "summary": "Suggest colleagues to CC", "description": "Up to eight contacts who look like the lead's colleagues: the same company name, or the same email domain when it belongs to a company rather than a personal mail service. Unsubscribed contacts and ones already copied are left out. Scope READ_CAMPAIGNS and READ_CONTACTS, org permission view_campaigns and view_contacts.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "contactId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "OK.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignLeadCCSuggestions" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "The campaign is not the caller's organization's.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/logs": { "get": { "operationId": "campaigns_list_logs", "summary": "Get campaign logs", "description": "Page through the campaign's activity log. Scope READ_CAMPAIGNS, org permission view_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque pagination cursor from the previous page.", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "required": false, "description": "Page size, 1 to 100 (default 50).", "schema": { "type": "integer", "default": 50, "maximum": 100, "minimum": 1 } } ], "responses": { "200": { "description": "A page of log entries.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignLogList" } } } }, "400": { "description": "Invalid cursor or limit.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/send-plan": { "get": { "operationId": "campaigns_send_plan", "summary": "Today's sending plan", "description": "What the campaign sends today and every limit that decided it, worked out through the scheduler's own gates. Nothing is stored or written. Scope READ_CAMPAIGNS, org permission view_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Today's plan.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignSendPlan" } } } }, "404": { "description": "Campaign not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/senders": { "get": { "operationId": "campaigns_list_senders", "summary": "List campaign senders", "description": "Return the campaign's explicit sender pool. Scope READ_CAMPAIGNS, org permission view_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The sender pool.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignSenderList" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "put": { "operationId": "campaigns_replace_senders", "summary": "Replace senders", "description": "Atomically replace the campaign's explicit sender pool. Scope WRITE_CAMPAIGNS, org permission manage_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignSendersReplace" } } } }, "responses": { "200": { "description": "The resulting sender pool.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignSenderList" } } } }, "400": { "description": "Validation error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/tracking-domain/verify": { "post": { "operationId": "campaigns_verify_tracking_domain", "summary": "Verify campaign tracking domain", "description": "Resolve the campaign-scoped tracking domain's CNAME and flip tracking_domain_verified on success. Scope WRITE_CAMPAIGNS, org permission manage_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "The tracking-domain status.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TrackingDomainStatus" } } } }, "400": { "description": "Verification failed or no domain configured.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaigns/{id}/steps": { "get": { "operationId": "campaigns_list_steps", "summary": "List steps", "description": "Return the campaign's sequence steps in order. Scope READ_CAMPAIGNS, org permission view_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The sequence steps (bare array, no envelope).", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CampaignStep" } } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "campaigns_create_step", "summary": "Create a step", "description": "Append a new sequence step. The body is optional and takes the same fields as the PATCH that updates a step, applied to the new step; without one the step is created with defaults. A body the update refuses creates nothing. Scope WRITE_CAMPAIGNS, org permission manage_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "The created step.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignStep" } } } }, "400": { "description": "The body is not valid, or the update it describes is refused.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignStepUpdate" } } } } } }, "/campaigns/{id}/steps/{sid}": { "patch": { "operationId": "campaigns_update_step", "summary": "Update a step", "description": "Patch a sequence step: copy, spacing, node kind, branching tree, or action config. Omitted fields are unchanged. Scope WRITE_CAMPAIGNS, org permission manage_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "sid", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignStepUpdate" } } } }, "responses": { "200": { "description": "The updated step.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignStep" } } } }, "400": { "description": "Validation error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "campaigns_delete_step", "summary": "Delete a step", "description": "Delete a sequence step. Scope WRITE_CAMPAIGNS, org permission manage_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "sid", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "Deleted (empty body)." }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/campaign-template-preview": { "post": { "operationId": "campaigns_template_preview", "summary": "Preview a template", "description": "Render subject and body templates against a sample (or supplied) contact and report parse errors plus unresolved tokens. No side effects. Scope READ_CAMPAIGNS, org permission view_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TemplatePreviewRequest" } } } }, "responses": { "200": { "description": "The rendered preview.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TemplatePreview" } } } }, "400": { "description": "Validation error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/generation/write": { "post": { "operationId": "campaigns_generate_writing", "summary": "Generate copy with the writing assistant", "description": "Generate outreach copy with the AI writing assistant. Gated to paid and free-trial orgs; consumes one AI credit (refunded on provider failure). Scope WRITE_CAMPAIGNS, org permission manage_campaigns.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GenerationWriteRequest" } } } }, "responses": { "200": { "description": "The generated copy.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GenerationWriteResult" } } } }, "400": { "description": "Validation error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "402": { "description": "Out of AI credits (code insufficient_credits).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/search": { "post": { "tags": [ "contacts" ], "operationId": "contacts_search", "summary": "Search contacts", "description": "Faceted, org-scoped contact search. Filters live in the body; pagination is via query params. Scope `READ_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "cursor", "in": "query", "required": false, "description": "Opaque pagination cursor from the previous page's pagination.next_cursor. It carries the exact position of the next page under the ordering it was issued for, so rows that share a sort value are never skipped or repeated. A malformed cursor, or one replayed with a different sort_by or reverse than it was issued under, is a 400.", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "required": false, "description": "Page size (numeric string). Default 50, max 100.", "schema": { "type": "string" } }, { "name": "category", "in": "query", "required": false, "description": "Convenience filter for a single category ID.", "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "required": false, "description": "All filters optional; an empty body matches every contact in the organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactSearchRequest" } } } }, "responses": { "200": { "description": "Matching contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactList" } } } }, "400": { "description": "Invalid body, cursor, or limit.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks READ_CONTACTS or caller lacks view_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts": { "post": { "tags": [ "contacts" ], "operationId": "contacts_create", "summary": "Create contacts", "description": "Creates one or more contacts. The body is a JSON array of contacts, or a single contact object, which is read as an array of one. The response is an array either way. Scope `WRITE_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "oneOf": [ { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/ContactCreate" } }, { "$ref": "#/components/schemas/ContactCreate" } ] } } } }, "responses": { "200": { "description": "The created contacts as a bare array.", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Contact" } } } } }, "400": { "description": "Empty array, too many contacts, or a body that is not a contact or an array of contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks WRITE_CONTACTS or caller lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "tags": [ "contacts" ], "operationId": "contacts_bulk_update", "summary": "Bulk update contacts", "description": "Applies one set of edits across a selection of contacts (up to 10000 by ID, or everything a filter matches, up to 250000): add/remove campaigns and categories, custom-field operations, and subscription. Scope `BULK_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactBulkUpdateRequest" } } } }, "responses": { "200": { "description": "The updated contacts as a bare array.", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Contact" } } } } }, "400": { "description": "A selection that names nothing, an explicit list over 10000 or an exclusion list over 250000 (`too_many_contacts`), a select-all with no filters, a filter matching no contacts, or a filter matching more than 250000 (`selection_too_large`).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks BULK_CONTACTS or caller lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "tags": [ "contacts" ], "operationId": "contacts_bulk_delete", "summary": "Bulk delete contacts", "description": "Deletes a selection of contacts: up to 10000 by ID, or everything a filter matches (up to 250000). Scope `BULK_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "description": "A JSON array of contact ID strings (1 to 10000), or a ContactSelection object naming a filter.", "content": { "application/json": { "schema": { "oneOf": [ { "type": "array", "minItems": 1, "maxItems": 10000, "items": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/schemas/ContactSelection" } ] } } } }, "responses": { "204": { "description": "Contacts deleted." }, "400": { "description": "A selection that names nothing, an explicit list over 10000 or an exclusion list over 250000 (`too_many_contacts`), a select-all with no filters, a filter matching no contacts, or a filter matching more than 250000 (`selection_too_large`).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks BULK_CONTACTS or caller lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/export": { "post": { "tags": [ "contacts" ], "operationId": "contacts_export", "summary": "Export contacts", "description": "Exports contacts to CSV, XLSX, or JSON. The response is the file itself, not JSON. Capped at 50,000 rows. Scope `READ_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactExportRequest" } } } }, "responses": { "200": { "description": "The export file as an attachment.", "headers": { "Content-Disposition": { "description": "attachment; filename=\"...\".", "schema": { "type": "string" } }, "X-Total-Rows": { "description": "Number of rows written.", "schema": { "type": "integer" } } }, "content": { "text/csv": { "schema": { "type": "string", "format": "binary" } }, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { "schema": { "type": "string", "format": "binary" } }, "application/json": { "schema": { "type": "string", "format": "binary" } } } }, "400": { "description": "Invalid format, scope, or filters.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks READ_CONTACTS or caller lacks view_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/import/preview": { "post": { "tags": [ "contacts" ], "operationId": "contacts_import_preview", "summary": "Preview an import", "description": "Uploads a CSV or XLSX file and returns detected columns plus a sample so the client can build a column mapping. Uploads capped at 50 MB. Scope `WRITE_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "required": [ "file" ], "properties": { "file": { "type": "string", "format": "binary", "description": "The CSV/XLSX upload." } } } } } }, "responses": { "200": { "description": "Detected columns, sample rows, and a suggested mapping.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactImportPreview" } } } }, "400": { "description": "Missing file, unsupported format, or over the size cap.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks WRITE_CONTACTS or caller lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/import/commit": { "post": { "tags": [ "contacts" ], "operationId": "contacts_import_commit", "summary": "Commit an import", "description": "Re-uploads the file with a mapping and dedup options, applies it, and returns per-row results. Imports capped at 50,000 rows. Scope `BULK_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "required": [ "file", "options" ], "properties": { "file": { "type": "string", "format": "binary", "description": "The CSV/XLSX upload (max 50 MB)." }, "options": { "type": "string", "description": "JSON-encoded ContactImportCommitOptions as a string." } } } } } }, "responses": { "200": { "description": "Per-row import results.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactImportResult" } } } }, "400": { "description": "Missing file/options, invalid mapping or dedup, or over a cap.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks BULK_CONTACTS or caller lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/imports": { "post": { "tags": [ "contacts" ], "operationId": "contacts_imports_create", "summary": "Create a background import", "description": "Uploads a CSV, TSV or XLSX file once and returns a draft with its preview, including every column's fill over the whole file. Nothing is written to contacts until the import is started. Max 50 MB and 50,000 rows; a workspace holds at most 10 drafts and running imports at once. Scope `WRITE_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "required": [ "file" ], "properties": { "file": { "type": "string", "format": "binary", "description": "The CSV/TSV/XLSX upload." } } } } } }, "responses": { "201": { "description": "The draft import, with preview.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactImport" } } } }, "400": { "description": "Missing file, unsupported format, empty, or over a cap.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks WRITE_CONTACTS or caller lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "The workspace already holds 10 drafts and running imports.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "get": { "tags": [ "contacts" ], "operationId": "contacts_imports_list", "summary": "List imports", "description": "The organization's background imports, newest first. Scope `READ_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 } }, { "name": "cursor", "in": "query", "schema": { "type": "string" }, "description": "pagination.next_cursor from the previous page." } ], "responses": { "200": { "description": "A page of imports.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactImportList" } } } }, "400": { "description": "Invalid cursor or limit.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks READ_CONTACTS or caller lacks view_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/imports/{id}": { "get": { "tags": [ "contacts" ], "operationId": "contacts_imports_get", "summary": "Get an import", "description": "An import with its progress. Once finished it carries its first 200 failed rows. Scope `READ_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Import id." } ], "responses": { "200": { "description": "The import.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactImport" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks READ_CONTACTS or caller lacks view_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such import in this organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "tags": [ "contacts" ], "operationId": "contacts_imports_save_draft", "summary": "Save a draft", "description": "Stores a draft's in-progress mapping and options without checking them, so a client can autosave and resume it. They are checked on start. Scope `WRITE_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Import id." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactImportOptions" } } } }, "responses": { "200": { "description": "The draft with its saved options.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactImport" } } } }, "400": { "description": "Malformed body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks WRITE_CONTACTS or caller lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such import in this organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "The import has already started.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/imports/{id}/analyze": { "post": { "tags": [ "contacts" ], "operationId": "contacts_imports_analyze", "summary": "Analyze an import", "description": "Reports what a draft would do under a mapping, over the whole file, writing nothing. Scope `WRITE_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Import id." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactImportAnalyzeRequest" } } } }, "responses": { "200": { "description": "What the import would do.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactImportAnalysis" } } } }, "400": { "description": "Invalid mapping.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks WRITE_CONTACTS or caller lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such import in this organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "The import has already started.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/imports/{id}/start": { "post": { "tags": [ "contacts" ], "operationId": "contacts_imports_start", "summary": "Start an import", "description": "Queues a draft with its mapping and options; the server applies it in chunks. Starting an import that has already started returns it unchanged. Scope `BULK_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Import id." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactImportOptions" } } } }, "responses": { "200": { "description": "The queued import.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactImport" } } } }, "400": { "description": "Invalid mapping, dedup, or target.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks BULK_CONTACTS or caller lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such import in this organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "The import was cancelled.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/imports/{id}/cancel": { "post": { "tags": [ "contacts" ], "operationId": "contacts_imports_cancel", "summary": "Cancel an import", "description": "Stops a draft, queued or running import. Rows already imported stay imported. Scope `BULK_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Import id." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "The import.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactImport" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks BULK_CONTACTS or caller lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such import in this organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/imports/{id}/failed.csv": { "get": { "tags": [ "contacts" ], "operationId": "contacts_imports_failed_csv", "summary": "Download failed rows", "description": "Every failed row as uploaded, under the file's own headers, followed by Line and Error columns. Scope `READ_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Import id." } ], "responses": { "200": { "description": "The failed rows.", "content": { "text/csv": { "schema": { "type": "string" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks READ_CONTACTS or caller lacks view_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such import in this organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/lookup": { "get": { "tags": [ "contacts" ], "operationId": "contacts_lookup", "summary": "Look up a contact by email", "description": "Resolves a sender address to a contact. Returns 200 with {\"contact\": null} when nothing matches. A display-name wrapped address (`Name `) is accepted and unwrapped. With `thread_id`, a sender whose address is not a contact resolves to the lead of the campaign send the thread answers; `match` says which one answered. Scope `READ_CONTACTS`, plus `READ_UNIBOX` with `thread_id`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "email", "in": "query", "required": false, "description": "The email address to resolve. Required unless thread_id is given.", "schema": { "type": "string" } }, { "name": "thread_id", "in": "query", "required": false, "description": "A unibox thread id. Used when the address is not a contact.", "schema": { "type": "string" } }, { "name": "account_id", "in": "query", "required": false, "description": "The mailbox holding the thread, to limit the thread match to it.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The resolved contact, or null.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactLookupResult" } } } }, "400": { "description": "Missing email and thread_id, or a malformed account_id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks READ_CONTACTS (or READ_UNIBOX with thread_id), caller lacks view_contacts (or access_unibox), or account_id is outside the key's email account allowlist.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/{id}": { "get": { "tags": [ "contacts" ], "operationId": "contacts_get", "summary": "Get a contact", "description": "Returns the hydrated contact 360 payload: the contact plus an engagement summary and, when present, suppression state. Scope `READ_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The hydrated contact.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactDetail" } } } }, "400": { "description": "Invalid contact ID.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks READ_CONTACTS or caller lacks view_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Contact not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "tags": [ "contacts" ], "operationId": "contacts_update", "summary": "Update a contact", "description": "Partially updates a single contact; only the fields present change. Category lists can be set wholesale or adjusted with diff-style add/remove. `email` replaces the contact's address and resets its verification verdict. Scope `WRITE_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactUpdate" } } } }, "responses": { "200": { "description": "The updated contact.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Contact" } } } }, "400": { "description": "Invalid contact ID or body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks WRITE_CONTACTS or caller lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Contact not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Another contact already uses the supplied email address (code contact_email_taken).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "tags": [ "contacts" ], "operationId": "contacts_delete", "summary": "Delete a contact", "description": "Deletes a single contact. Scope `WRITE_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Contact deleted." }, "400": { "description": "Invalid contact ID.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks WRITE_CONTACTS or caller lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Contact not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/{id}/emails": { "get": { "tags": [ "contacts" ], "operationId": "contacts_emails_list", "summary": "List emails sent to a contact", "description": "One row per email sent (or attempted) to the contact, newest first. Keyset paginated on (created_at, task_id); pass both before_at and before_id together. Scope `READ_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "limit", "in": "query", "required": false, "description": "Page size, 1 to 200 (default 50).", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } }, { "name": "before_at", "in": "query", "required": false, "description": "created_at of the last row from the previous page (RFC 3339 nano).", "schema": { "type": "string", "format": "date-time" } }, { "name": "before_id", "in": "query", "required": false, "description": "task_id of the last row from the previous page.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Sent emails.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactSentEmailList" } } } }, "400": { "description": "Invalid contact ID or limit.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks READ_CONTACTS or caller lacks view_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Contact not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/{id}/timeline": { "get": { "tags": [ "contacts" ], "operationId": "contacts_timeline_list", "summary": "List a contact's timeline", "description": "Merged activity feed: sends, opens, clicks, replies, bounces, deliverability/suppression events, notes, meeting bookings, lifecycle events, and website page views. Requires a selected organization. Paginate with the opaque `cursor` from `pagination.next_cursor`; the cursor carries the exact position of the last event (time, source, row), so events that share a timestamp are never skipped or repeated. Scope `READ_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "limit", "in": "query", "required": false, "description": "Page size, 1 to 200 (default 50).", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque pagination cursor from `pagination.next_cursor`. A malformed cursor is a 400.", "schema": { "type": "string" } }, { "name": "before", "in": "query", "required": false, "deprecated": true, "description": "Deprecated: use `cursor`. Returns the events strictly older than this timestamp (RFC 3339 nano), which can skip events that share an instant with the page boundary. Ignored when `cursor` is set.", "schema": { "type": "string", "format": "date-time" } } ], "responses": { "200": { "description": "A page of timeline events with the pagination envelope.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactTimelineResult" } } } }, "400": { "description": "Invalid contact ID, limit, cursor or before timestamp, or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks READ_CONTACTS or caller lacks view_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Contact not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/{id}/activities": { "get": { "tags": [ "contacts" ], "operationId": "contacts_activities_list", "summary": "List a contact's activities", "description": "Structured CRM activity log for a contact. Requires a selected organization. Scope `READ_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "limit", "in": "query", "required": false, "description": "Page size, 1 to 100 (default 50).", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from the previous page's pagination.next_cursor.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "CRM activity log.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactActivityList" } } } }, "400": { "description": "Invalid contact ID, cursor, or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks READ_CONTACTS or caller lacks view_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Contact not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/{id}/notes": { "get": { "tags": [ "contacts" ], "operationId": "contacts_notes_list", "summary": "List a contact's notes", "description": "CRM notes attached to a contact, newest first. Requires a selected organization. Scope `READ_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "limit", "in": "query", "required": false, "description": "Page size, 1 to 100 (default 50).", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from the previous page's pagination.next_cursor.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Contact notes.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactNoteList" } } } }, "400": { "description": "Invalid contact ID, cursor, or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks READ_CONTACTS or caller lacks view_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Contact not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "tags": [ "contacts" ], "operationId": "contacts_notes_create", "summary": "Create a contact note", "description": "Adds a note to a contact. Requires a selected organization. Scope `WRITE_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactNoteCreate" } } } }, "responses": { "201": { "description": "The created note.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactNote" } } } }, "400": { "description": "Invalid contact ID, missing/too-long content, or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks WRITE_CONTACTS or caller lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Contact not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/{id}/notes/{noteId}": { "patch": { "tags": [ "contacts" ], "operationId": "contacts_notes_update", "summary": "Update a contact note", "description": "Edits a note's content. Requires a selected organization. Scope `WRITE_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "noteId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactNoteUpdate" } } } }, "responses": { "200": { "description": "The updated note.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactNote" } } } }, "400": { "description": "Invalid IDs, body, or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks WRITE_CONTACTS or caller lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Contact or note not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "tags": [ "contacts" ], "operationId": "contacts_notes_delete", "summary": "Delete a contact note", "description": "Deletes a note. Requires a selected organization. Scope `WRITE_CONTACTS`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "noteId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Note deleted." }, "400": { "description": "Invalid IDs or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks WRITE_CONTACTS or caller lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Contact or note not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/contacts/{id}/deals": { "get": { "tags": [ "contacts" ], "operationId": "contacts_deals_list", "summary": "List a contact's deals", "description": "CRM deals associated with a contact, returned as a bare JSON array. Scope `READ_CRM`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The contact's deals.", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Deal" } } } } }, "400": { "description": "Invalid contact ID.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks READ_CRM or caller lacks view_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Contact not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/unibox": { "get": { "operationId": "unibox_list", "summary": "List incoming mail", "description": "Org-wide inbox list, collapsed to one row per thread (newest message), with filtering and cursor pagination. Excludes snoozed threads unless `snoozed=true`, and the `spam`, `trash` and `archive` folders unless `folder` selects one of them or `include_archived=true` is passed.", "tags": [ "unibox" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "cursor", "in": "query", "required": false, "description": "Opaque pagination cursor from a previous response.", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "required": false, "description": "Page size, clamped to the server min/max.", "schema": { "type": "integer", "default": 50, "maximum": 100 } }, { "name": "from", "in": "query", "required": false, "description": "Filter by sender address (substring).", "schema": { "type": "string" } }, { "name": "subject", "in": "query", "required": false, "description": "Filter by subject (substring).", "schema": { "type": "string" } }, { "name": "folder", "in": "query", "required": false, "description": "Canonical folder scope. Omit for every working folder: `spam`, `trash` and `archive` stay out.", "schema": { "type": "string", "enum": [ "inbox", "sent", "drafts", "archive", "spam", "trash" ] } }, { "name": "include_archived", "in": "query", "required": false, "description": "`true` puts archived conversations back into the result, which is what the All mail view does. Ignored when `folder` is set.", "schema": { "type": "boolean" } }, { "name": "unseen", "in": "query", "required": false, "description": "`true` returns only threads with unread messages.", "schema": { "type": "boolean" } }, { "name": "awaiting_reply", "in": "query", "required": false, "description": "`true` returns only threads whose latest message was sent by one of your mailboxes.", "schema": { "type": "boolean" } }, { "name": "automated", "in": "query", "required": false, "description": "`true` returns only conversations no person wrote in (security alerts, notifications, bounces, auto-replies), as judged by automatic inbox tagging. `false` leaves them out, which is how the dashboard's Inbox reads. Omit for both.", "schema": { "type": "boolean" } }, { "name": "snoozed", "in": "query", "required": false, "description": "`true` returns only snoozed threads. Omit to exclude snoozed threads.", "schema": { "type": "string" } }, { "name": "since", "in": "query", "required": false, "description": "Lower bound on date, `YYYY-MM-DD`.", "schema": { "type": "string", "format": "date" } }, { "name": "until", "in": "query", "required": false, "description": "Upper bound on date, `YYYY-MM-DD`.", "schema": { "type": "string", "format": "date" } }, { "name": "email_id", "in": "query", "required": false, "description": "Restrict to a single mailbox by UUID.", "schema": { "type": "string", "format": "uuid" } }, { "name": "email_ids", "in": "query", "required": false, "description": "Comma-separated mailbox UUIDs. A thread matches if it landed in any of them.", "schema": { "type": "string" } }, { "name": "category_ids", "in": "query", "required": false, "description": "Comma-separated conversation-label UUIDs. A thread matches if it carries any of them.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Inbox list page.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxThreadList" } } } }, "400": { "description": "Invalid cursor, limit, or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing scope/permission, or organization lacks unified-inbox access.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/unibox/count": { "get": { "operationId": "unibox_count", "summary": "Get unread count", "description": "Unread conversations in the Inbox folder, optionally scoped to one mailbox. Snoozed conversations and other folders are not counted.", "tags": [ "unibox" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "email_id", "in": "query", "required": false, "description": "Optional mailbox UUID to count unread for a single mailbox.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Unread count.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxCount" } } } }, "400": { "description": "No organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing scope/permission, or organization lacks unified-inbox access.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/unibox/overview": { "get": { "operationId": "unibox_overview", "summary": "Get inbox overview", "description": "Rolls up scope-rail and metric-strip counts (unread, today, week, snoozed, awaiting-reply, pending-scheduled) plus per-mailbox, per-tag, and per-conversation-label breakdowns.", "tags": [ "unibox" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Inbox overview rollup.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxOverview" } } } }, "400": { "description": "No organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing scope/permission, or organization lacks unified-inbox access.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/unibox/thread": { "get": { "operationId": "unibox_get_thread", "summary": "Get a thread", "description": "Every message in a single conversation, with cursor pagination. With no `email_id` the thread is read across every mailbox in the organization.", "tags": [ "unibox" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "thread_id", "in": "query", "required": true, "description": "The thread to read. Also accepted as `id`.", "schema": { "type": "string" } }, { "name": "email_id", "in": "query", "required": false, "description": "Optional mailbox UUID to scope the thread to one mailbox. Also accepted as `email`.", "schema": { "type": "string", "format": "uuid" } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque pagination cursor.", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "required": false, "description": "Page size. Out-of-range values return 400.", "schema": { "type": "integer", "default": 50, "maximum": 100 } } ], "responses": { "200": { "description": "Thread messages page.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxMessageList" } } } }, "400": { "description": "Missing `thread_id`, invalid cursor/limit, or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing scope/permission, or organization lacks unified-inbox access.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/unibox/thread/labels": { "get": { "operationId": "unibox_get_thread_labels", "summary": "Get thread labels", "description": "Conversation labels (the workspace's categories) attached to a thread.", "tags": [ "unibox" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "thread_id", "in": "query", "required": true, "description": "The thread to read labels for. Also accepted as `id`.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Label set wrapped in a `data` array.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxLabelList" } } } }, "400": { "description": "Missing `thread_id` or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing scope/permission, or organization lacks unified-inbox access.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "put": { "operationId": "unibox_set_thread_labels", "summary": "Set thread labels", "description": "Replaces the full conversation-label set on a thread. `category_ids` is the desired set, so the call is idempotent and retries are naturally safe.", "tags": [ "unibox" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxSetThreadLabelsRequest" } } } }, "responses": { "200": { "description": "Resulting label set wrapped in a `data` array.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxLabelList" } } } }, "400": { "description": "Missing `thread_id` or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing scope/permission, or organization lacks unified-inbox access.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/unibox/seen": { "patch": { "operationId": "unibox_mark_seen", "summary": "Mark messages seen", "description": "Marks messages as read or unread, org-wide. Name them with `email_ids`, whole conversations with `thread_ids`, or sweep a folder with `folder`. Up to 500 ids of each per call.", "tags": [ "unibox" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxMarkSeenRequest" } } } }, "responses": { "200": { "description": "Echoes the request back.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxMarkSeenRequest" } } } }, "400": { "description": "Invalid body, more than 500 ids, or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing scope/permission, or organization lacks unified-inbox access.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/unibox/folder": { "patch": { "operationId": "unibox_move_folder", "summary": "Move conversations between folders", "description": "Re-files messages into Inbox, Archive or Trash, org-wide. Name them with `email_ids`, whole conversations with `thread_ids`, or both; up to 500 of each. Prefer `thread_ids`: filing part of a conversation leaves it listed.\n\nThe move is then relayed to each mailbox with `relay_folder_moves` on (the default): after the response and best-effort, the provider's copy is archived, moved to its trash, or put back in its inbox. A later sync will not undo a filing either way: Warmbly tracks the provider's own placement separately and follows it only when the provider itself moves the message. `sent`, `drafts` and `spam` are placements the provider reaches, so they are rejected here with a `400`.", "tags": [ "unibox" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxMoveFolderRequest" } } } }, "responses": { "200": { "description": "Echoes the request back.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxMoveFolderRequest" } } } }, "400": { "description": "Invalid body, more than 500 ids, a folder outside inbox/archive/trash, or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing scope/permission, or organization lacks unified-inbox access.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/unibox/reply": { "post": { "operationId": "unibox_reply", "summary": "Reply from the inbox", "description": "Sends or schedules a reply or forward from any mailbox in the organization, routed through the per-mailbox scheduler according to `send_mode`. Requires an active organization. `thread_id` names the conversation; the Gmail thread handle is only used by a mailbox holding a message in that thread (or continuing a thread its own earlier reply started), and a reply from any other mailbox threads for the recipient on In-Reply-To and References alone. With `forward_message_id` the stored message is attached under the body and the mailbox signature, so the body is an optional note.", "tags": [ "unibox" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxReplyRequest" } } } }, "responses": { "200": { "description": "Reply queued or scheduled.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxReplyResult" } } } }, "400": { "description": "Invalid body, invalid mailbox UUID, missing future `scheduled_at`, or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing scope/permission (a forward also needs `READ_UNIBOX`), organization lacks unified-inbox access, or the API key is not allowed the sending mailbox or the mailbox of the forwarded message.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "The sending mailbox or the message named by `forward_message_id` is not in the organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/unibox/snoozes": { "get": { "operationId": "unibox_list_snoozes", "summary": "List active snoozes", "description": "Your active thread snoozes.", "tags": [ "unibox" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Active snoozes wrapped in a `data` array.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxSnoozeList" } } } }, "400": { "description": "No organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing scope/permission, or organization lacks unified-inbox access.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/unibox/snooze": { "post": { "operationId": "unibox_snooze", "summary": "Snooze one or more threads", "description": "Hides threads from your inbox until `snoozed_until` passes. Upsert semantics: a second call on the same thread updates the time in place. A request naming one thread answers with that row; one naming several answers with `data`.", "tags": [ "unibox" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxSnoozeRequest" } } } }, "responses": { "200": { "description": "The created or updated snooze.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxSnooze" } } } }, "400": { "description": "Invalid body or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing scope/permission, or organization lacks unified-inbox access.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "unibox_unsnooze", "summary": "Unsnooze one or more threads", "description": "Un-snoozes threads immediately. Idempotent: deleting a snooze that does not exist still succeeds with 204.", "tags": [ "unibox" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "thread_id", "in": "query", "required": true, "description": "The thread to un-snooze, or a comma-separated list of them.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Snooze removed (or already absent). Empty body." }, "400": { "description": "Missing `thread_id` or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing scope/permission, or organization lacks unified-inbox access.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/unibox/scheduled": { "get": { "operationId": "unibox_list_scheduled", "summary": "List scheduled sends", "description": "Outbound emails queued from the organization's mailboxes but not yet sent, whichever member queued them. An API key limited to certain mailboxes sees only their sends. Pass `thread_id` to scope to a single conversation; the response shape is identical either way.", "tags": [ "unibox" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "thread_id", "in": "query", "required": false, "description": "Restrict to scheduled sends queued into one thread.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Queued message previews wrapped in a `data` array.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxScheduledList" } } } }, "400": { "description": "No organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing scope/permission, or organization lacks unified-inbox access.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/unibox/scheduled/{task_id}": { "delete": { "operationId": "unibox_cancel_scheduled", "summary": "Cancel a scheduled send", "description": "Cancels a pending scheduled send from any of the organization's mailboxes (for an API key limited to certain mailboxes, from those) before it fires. The queued task is marked cancelled and short-circuits to a no-op when its run time arrives.", "tags": [ "unibox" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "task_id", "in": "path", "required": true, "description": "UUID of the scheduled task to cancel.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Scheduled send cancelled. Empty body." }, "400": { "description": "Invalid task id or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing scope/permission, or organization lacks unified-inbox access.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Scheduled send not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/unibox/{id}": { "get": { "operationId": "unibox_get", "summary": "Get a message by id", "description": "A single message by its UUID, including the full envelope and body.", "tags": [ "unibox" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "UUID of the message.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The message.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UniboxEmail" } } } }, "400": { "description": "Invalid message id or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing scope/permission, or organization lacks unified-inbox access.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Message not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/crm/pipelines": { "get": { "operationId": "crm_list_pipelines", "summary": "List pipelines", "description": "Return every pipeline in the organization, each with its ordered stages. Returns a bare array, not a list envelope.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Array of pipelines (each with its stages).", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Pipeline" } } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "crm_create_pipeline", "summary": "Create pipeline", "description": "Create a pipeline, optionally seeding it with an ordered set of stages.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreatePipeline" } } } }, "responses": { "201": { "description": "Created pipeline (including its stages).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Pipeline" } } } }, "400": { "description": "Invalid request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/crm/pipelines/{id}": { "get": { "operationId": "crm_get_pipeline", "summary": "Get pipeline", "description": "Fetch a single pipeline with its stages.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Pipeline ID.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The pipeline.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Pipeline" } } } }, "400": { "description": "Malformed path parameter.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Pipeline not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "crm_update_pipeline", "summary": "Update pipeline", "description": "Rename a pipeline. Only the name can be changed here; stages have their own endpoints.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Pipeline ID.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdatePipeline" } } } }, "responses": { "200": { "description": "Updated pipeline.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Pipeline" } } } }, "400": { "description": "Invalid request body or path parameter.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Pipeline not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "crm_delete_pipeline", "summary": "Delete pipeline", "description": "Delete a pipeline and its stages.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Pipeline ID.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Pipeline deleted." }, "400": { "description": "Malformed path parameter.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Pipeline not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/crm/pipelines/{id}/stages": { "post": { "operationId": "crm_create_stage", "summary": "Create stage", "description": "Append a stage to a pipeline.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Pipeline ID.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreatePipelineStage" } } } }, "responses": { "201": { "description": "Created stage.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PipelineStage" } } } }, "400": { "description": "Invalid request body or path parameter.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Pipeline not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/crm/pipelines/{id}/stages/{stageId}": { "patch": { "operationId": "crm_update_stage", "summary": "Update stage", "description": "Rename or recolor a stage.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Pipeline ID.", "schema": { "type": "string", "format": "uuid" } }, { "name": "stageId", "in": "path", "required": true, "description": "Stage ID.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdatePipelineStage" } } } }, "responses": { "200": { "description": "Updated stage.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PipelineStage" } } } }, "400": { "description": "Invalid request body or path parameter.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Pipeline or stage not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "crm_delete_stage", "summary": "Delete stage", "description": "Remove a stage from a pipeline.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Pipeline ID.", "schema": { "type": "string", "format": "uuid" } }, { "name": "stageId", "in": "path", "required": true, "description": "Stage ID.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Stage deleted." }, "400": { "description": "Malformed path parameter.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Pipeline or stage not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/crm/deals": { "get": { "operationId": "crm_list_deals", "summary": "List deals", "description": "List deals with optional pipeline, stage, and status filters, keyset-paginated.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "pipeline_id", "in": "query", "required": false, "description": "Restrict to deals in this pipeline.", "schema": { "type": "string", "format": "uuid" } }, { "name": "stage_id", "in": "query", "required": false, "description": "Restrict to deals in this stage.", "schema": { "type": "string", "format": "uuid" } }, { "name": "status", "in": "query", "required": false, "description": "Restrict to a deal status.", "schema": { "type": "string", "enum": [ "open", "won", "lost" ] } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque keyset cursor from a previous page's pagination.next_cursor.", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "required": false, "description": "Page size, 1 to 100.", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 } } ], "responses": { "200": { "description": "Page of deals.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DealList" } } } }, "400": { "description": "Invalid cursor, limit, or filter value.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "crm_create_deal", "summary": "Create deal", "description": "Create a deal in a pipeline stage, optionally linked to a contact and attributed to a campaign and source mailbox. New deals default to status open.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateDeal" } } } }, "responses": { "201": { "description": "Created deal.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Deal" } } } }, "400": { "description": "Invalid request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/crm/deals/search": { "post": { "operationId": "crm_search_deals", "summary": "Search deals", "description": "Faceted, offset-paginated deal search. Every filter is optional; an empty body matches every deal in the organization. Filters go in the JSON body; limit and offset are query params.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "limit", "in": "query", "required": false, "description": "Page size, 1 to 200.", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from a previous response's pagination.next_cursor. Omit for the first page.", "schema": { "type": "string" } } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchDeals" } } } }, "responses": { "200": { "description": "Offset-paginated deal results with an exact total.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DealsSearchResult" } } } }, "400": { "description": "Invalid limit, offset, or filter body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/crm/deals/summary": { "post": { "operationId": "crm_deals_summary", "summary": "Deals summary", "description": "Aggregate counts and value sums over the same filter body as deal search, including per-stage totals. All facets are optional.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchDeals" } } } }, "responses": { "200": { "description": "Aggregate deal totals.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DealsSummary" } } } }, "400": { "description": "Invalid filter body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/crm/deals/{id}": { "get": { "operationId": "crm_get_deal", "summary": "Get deal", "description": "Fetch a single deal. Joined contact, stage, and campaign_name are only populated by the list and search queries, not by this single-row read.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Deal ID.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The deal.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Deal" } } } }, "400": { "description": "Malformed path parameter.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Deal not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "crm_update_deal", "summary": "Update deal", "description": "Update a deal. Moving it to a different stage_id records a stage-change activity, and setting status to won or lost stamps the corresponding close timestamp.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Deal ID.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateDeal" } } } }, "responses": { "200": { "description": "Updated deal.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Deal" } } } }, "400": { "description": "Invalid request body or path parameter.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Deal not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "crm_delete_deal", "summary": "Delete deal", "description": "Delete a deal.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Deal ID.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Deal deleted." }, "400": { "description": "Malformed path parameter.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Deal not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/crm/task-types": { "get": { "operationId": "crm_list_task_types", "summary": "List task types", "description": "List the organization's CRM task types. A default set is seeded the first time an org lists its types. Returns a data array with no pagination envelope.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Task types.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CRMTaskTypeList" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "crm_create_task_type", "summary": "Create task type", "description": "Create a CRM task type.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateCRMTaskType" } } } }, "responses": { "201": { "description": "Created task type.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CRMTaskType" } } } }, "400": { "description": "Invalid request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/crm/task-types/{id}": { "patch": { "operationId": "crm_update_task_type", "summary": "Update task type", "description": "Rename, recolor, or reorder a task type.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Task type ID.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateCRMTaskType" } } } }, "responses": { "200": { "description": "Updated task type.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CRMTaskType" } } } }, "400": { "description": "Invalid request body or path parameter.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Task type not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "crm_delete_task_type", "summary": "Delete task type", "description": "Delete a task type. Tasks reference their type by name, so existing tasks keep their label and fall back to a neutral color rather than being orphaned.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Task type ID.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Task type deleted." }, "400": { "description": "Malformed path parameter.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Task type not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/crm/tasks": { "get": { "operationId": "crm_list_tasks", "summary": "List tasks", "description": "List CRM tasks with optional contact, deal, assignee, and status filters, keyset-paginated.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "contact_id", "in": "query", "required": false, "description": "Restrict to tasks linked to this contact.", "schema": { "type": "string", "format": "uuid" } }, { "name": "deal_id", "in": "query", "required": false, "description": "Restrict to tasks linked to this deal.", "schema": { "type": "string", "format": "uuid" } }, { "name": "assigned_to", "in": "query", "required": false, "description": "Restrict to tasks assigned to this user.", "schema": { "type": "string", "format": "uuid" } }, { "name": "status", "in": "query", "required": false, "description": "Restrict to a task status.", "schema": { "type": "string", "enum": [ "pending", "in_progress", "completed", "cancelled" ] } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque keyset cursor from a previous page's pagination.next_cursor.", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "required": false, "description": "Page size, 1 to 100.", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 } } ], "responses": { "200": { "description": "Page of tasks.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CRMTaskList" } } } }, "400": { "description": "Invalid cursor, limit, or filter value.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "crm_create_task", "summary": "Create task", "description": "Create a CRM task, optionally linked to a contact and deal and assigned to a user or team. created_by is set to the authenticated user.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateCRMTask" } } } }, "responses": { "201": { "description": "Created task.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CRMTask" } } } }, "400": { "description": "Invalid request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "crm_bulk_update_tasks", "summary": "Bulk update tasks", "description": "Write a status, a priority, or both onto every task in a selection: the ids given, or every task the supplied filter matches minus the ids in exclude.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkUpdateTasks" } } } }, "responses": { "200": { "description": "Number of tasks updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkTasksResponse" } } } }, "400": { "description": "Invalid body, an unknown status or priority, a selection with no ids, more than 1000 ids or more than 50000 exclusions (too_many_tasks), a filter naming something that is not an id (invalid_filter), or a selection resolving to more than 50000 tasks (selection_too_large).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "crm_bulk_delete_tasks", "summary": "Bulk delete tasks", "description": "Delete every task in a selection. The body is the selection object, or a bare array of task ids.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "oneOf": [ { "$ref": "#/components/schemas/TaskSelection" }, { "type": "array", "minItems": 1, "maxItems": 1000, "items": { "type": "string", "format": "uuid" }, "description": "A bare list of task ids, equivalent to sending {\"tasks\": [...]}." } ], "description": "The selection object, or a bare array of task ids." } } } }, "responses": { "200": { "description": "Number of tasks deleted.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkTasksResponse" } } } }, "400": { "description": "Invalid body, a task id that is not an id, a selection with no ids, more than 1000 ids or more than 50000 exclusions (too_many_tasks), a filter naming something that is not an id (invalid_filter), or a selection resolving to more than 50000 tasks (selection_too_large).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/crm/tasks/search": { "post": { "operationId": "crm_search_tasks", "summary": "Search tasks", "description": "Faceted, offset-paginated task search. Every filter is optional; an empty body matches every task in the organization. Filters go in the JSON body; limit and offset are query params.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "limit", "in": "query", "required": false, "description": "Page size, 1 to 200.", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from a previous response's pagination.next_cursor. Omit for the first page.", "schema": { "type": "string" } } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchTasks" } } } }, "responses": { "200": { "description": "Offset-paginated task results with an exact total.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TasksSearchResult" } } } }, "400": { "description": "Invalid limit, offset, or filter body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/crm/tasks/summary": { "post": { "operationId": "crm_tasks_summary", "summary": "Tasks summary", "description": "Aggregate counts over the same filter body as task search (by status, overdue, high priority). All facets are optional.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchTasks" } } } }, "responses": { "200": { "description": "Aggregate task counts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TasksSummary" } } } }, "400": { "description": "Invalid filter body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/crm/tasks/{id}": { "get": { "operationId": "crm_get_task", "summary": "Get task", "description": "Fetch a single CRM task.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Task ID.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The task.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CRMTask" } } } }, "400": { "description": "Malformed path parameter.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Task not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "crm_update_task", "summary": "Update task", "description": "Update a CRM task. Setting status to completed stamps the completion timestamp.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Task ID.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateCRMTask" } } } }, "responses": { "200": { "description": "Updated task.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CRMTask" } } } }, "400": { "description": "Invalid request body or path parameter.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Task not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "crm_delete_task", "summary": "Delete task", "description": "Delete a CRM task.", "tags": [ "crm" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Task ID.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Task deleted." }, "400": { "description": "Malformed path parameter.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Task not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/api-keys": { "get": { "operationId": "api-keys_list", "summary": "List API keys", "description": "Returns the organization's API keys, newest first. The plaintext secret is never included.", "tags": [ "api-keys" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "cursor", "in": "query", "required": false, "description": "Opaque pagination token from the previous page's pagination.next_cursor. Omit for the first page.", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "required": false, "description": "Page size, 1 to 100. Defaults to 50.", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 } } ], "responses": { "200": { "description": "A page of API keys.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIKeyList" } } } }, "400": { "description": "Invalid cursor or limit, or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthenticated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing API_KEYS scope or manage_api_keys org permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "api-keys_create", "summary": "Create an API key", "description": "Creates a new key and returns the plaintext secret exactly once. Unknown permission bits are rejected.", "tags": [ "api-keys" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateAPIKey" } } } }, "responses": { "201": { "description": "The created key, including the one-time secret.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIKeyWithSecret" } } } }, "400": { "description": "Invalid body, no organization selected, or permission bitmask contains unknown bits.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthenticated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing API_KEYS scope or manage_api_keys org permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/api-keys/permissions": { "get": { "operationId": "api-keys_list_permissions", "summary": "List available permissions", "description": "Returns the catalog of permission bits plus the read_only and full_access presets.", "tags": [ "api-keys" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The permission catalog and presets.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIPermissionCatalog" } } } }, "401": { "description": "Unauthenticated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing API_KEYS scope or manage_api_keys org permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/api-keys/usage/summary": { "get": { "operationId": "api-keys_usage_summary", "summary": "Usage summary", "description": "Org-level usage strip: key counts by status plus a 24-hour request, error, and latency rollup.", "tags": [ "api-keys" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The usage summary object.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIKeyUsageSummary" } } } }, "400": { "description": "No organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthenticated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing API_KEYS scope or manage_api_keys org permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/api-keys/usage/analytics": { "get": { "operationId": "api-keys_usage_analytics", "summary": "Org-wide usage analytics", "description": "Time-bucketed request series plus a per-endpoint breakdown for the whole organization. For this org-wide form api_key_id is the all-zero UUID.", "tags": [ "api-keys" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "from", "in": "query", "required": false, "description": "Start of the window (RFC3339). Defaults to 24 hours before to.", "schema": { "type": "string", "format": "date-time" } }, { "name": "to", "in": "query", "required": false, "description": "End of the window (RFC3339). Defaults to now.", "schema": { "type": "string", "format": "date-time" } }, { "name": "interval", "in": "query", "required": false, "description": "Bucket granularity.", "schema": { "type": "string", "enum": [ "minute", "hour", "day" ] } } ], "responses": { "200": { "description": "The analytics payload.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIKeyAnalytics" } } } }, "400": { "description": "No organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthenticated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing API_KEYS scope or manage_api_keys org permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/api-keys/{id}": { "get": { "operationId": "api-keys_get", "summary": "Get an API key", "description": "Returns a single key by id. The secret is never included.", "tags": [ "api-keys" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIKey" } } } }, "400": { "description": "No organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthenticated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing API_KEYS scope or manage_api_keys org permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Invalid UUID or key not found in this organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "api-keys_update", "summary": "Update an API key", "description": "Updates the mutable fields of a key. Every field is optional; only the fields you send are changed. The secret cannot be rotated here.", "tags": [ "api-keys" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateAPIKey" } } } }, "responses": { "200": { "description": "The updated API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIKey" } } } }, "400": { "description": "Invalid body, no organization selected, or permission bitmask contains unknown bits.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthenticated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing API_KEYS scope or manage_api_keys org permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Invalid UUID or key not found in this organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "api-keys_revoke", "summary": "Revoke an API key", "description": "Revokes a key immediately. The key stops authenticating right away; this is not reversible.", "tags": [ "api-keys" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "reason", "in": "query", "required": false, "description": "Optional revocation note stored on the key. Defaults to \"Revoked by user\".", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "Revocation status envelope.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIKeyRevokeResult" } } } }, "400": { "description": "No organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthenticated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing API_KEYS scope or manage_api_keys org permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Invalid UUID or key not found in this organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/api-keys/{id}/permanent": { "delete": { "operationId": "api-keys_delete", "summary": "Delete an API key", "description": "Removes a revoked or expired key from the workspace for good, along with its usage logs. A key that could still authenticate is refused with a 409: revoke it first, so what ended the credential stays on the record. A key past its expires_at can be deleted directly, since it already authenticates nothing.", "tags": [ "api-keys" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "Deletion status envelope.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIKeyDeleteResult" } } } }, "400": { "description": "No organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthenticated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing API_KEYS scope or manage_api_keys org permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Invalid UUID or key not found in this organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "The key can still authenticate. Revoke it first.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/api-keys/{id}/analytics": { "get": { "operationId": "api-keys_analytics", "summary": "Per-key usage analytics", "description": "Time-bucketed request series plus a per-endpoint breakdown for a single key. Pass the literal id value `all` for the org-wide aggregate.", "tags": [ "api-keys" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The API key id, or the literal `all` for the org-wide aggregate.", "schema": { "type": "string" } }, { "name": "from", "in": "query", "required": false, "description": "Start of the window (RFC3339). Defaults to 24 hours before to.", "schema": { "type": "string", "format": "date-time" } }, { "name": "to", "in": "query", "required": false, "description": "End of the window (RFC3339). Defaults to now.", "schema": { "type": "string", "format": "date-time" } }, { "name": "interval", "in": "query", "required": false, "description": "Bucket granularity.", "schema": { "type": "string", "enum": [ "minute", "hour", "day" ] } } ], "responses": { "200": { "description": "The analytics payload.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIKeyAnalytics" } } } }, "400": { "description": "No organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthenticated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing API_KEYS scope or manage_api_keys org permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Invalid UUID (when not `all`) or key not found in this organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/api-keys/{id}/logs": { "get": { "operationId": "api-keys_list_logs", "summary": "List per-key usage logs", "description": "Returns the recent raw request entries for a single key, newest first.", "tags": [ "api-keys" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque pagination token from the previous page's pagination.next_cursor.", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "required": false, "description": "Page size, 1 to 200. Defaults to 50.", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } } ], "responses": { "200": { "description": "A page of usage log entries.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIKeyUsageLogList" } } } }, "400": { "description": "Invalid cursor, or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthenticated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing API_KEYS scope or manage_api_keys org permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Invalid UUID or key not found in this organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/webhooks": { "get": { "operationId": "webhooks_list", "tags": [ "webhooks" ], "summary": "List webhook endpoints", "description": "Returns every webhook endpoint configured for the caller's organization, plus the canonical `event_types` vocabulary for building a picker. Secrets are never returned. This endpoint does NOT use the `data` + `pagination` cursor envelope. Requires the `WEBHOOKS` scope and the `manage_settings` org permission.", "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The organization's webhook endpoints and the full event vocabulary.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookEndpointList" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "webhooks_create", "tags": [ "webhooks" ], "summary": "Create a webhook endpoint", "description": "Creates a new event subscription. The `url` must be HTTPS and resolve to a publicly routable host (loopback, private, and link-local targets are rejected unless the server runs with unsafe webhook URLs enabled for local or self-hosted development). The response is the only time the signing `secret` (prefixed `whsec_`) is returned, so capture it immediately. Requires the `WEBHOOKS` scope and the `manage_settings` org permission.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookEndpointRequest" } } } }, "responses": { "201": { "description": "The created endpoint, including the one-time `secret`.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookEndpointWithSecret" } } } }, "400": { "description": "Invalid payload, non-HTTPS or non-routable url, or unknown event type.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/webhooks/{id}": { "patch": { "operationId": "webhooks_update", "tags": [ "webhooks" ], "summary": "Update a webhook endpoint", "description": "Replaces the endpoint's url, description, event filter, and enabled state with the values sent (send the complete desired state; `event_types` is overwritten, not merged). The signing secret is not changed here; use the rotate-secret endpoint. Requires the `WEBHOOKS` scope and the `manage_settings` org permission.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The endpoint id to update.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookEndpointRequest" } } } }, "responses": { "200": { "description": "The updated endpoint (no secret).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookEndpoint" } } } }, "400": { "description": "Invalid payload, invalid endpoint id, non-HTTPS or non-routable url, or unknown event type.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Endpoint not found or not owned by your organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "webhooks_delete", "tags": [ "webhooks" ], "summary": "Delete a webhook endpoint", "description": "Deletes a subscription and cascades to its delivery history. Requires the `WEBHOOKS` scope and the `manage_settings` org permission.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The endpoint id to delete.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Deleted. Empty body." }, "400": { "description": "Invalid endpoint id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Endpoint not found or not owned by your organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/webhooks/{id}/rotate-secret": { "post": { "operationId": "webhooks_rotate_secret", "tags": [ "webhooks" ], "summary": "Rotate the signing secret", "description": "Issues a new HMAC signing secret and returns it once. In-flight deliveries already signed continue to verify against the old secret until they settle; new deliveries use the new secret. Update your `X-Warmbly-Signature` verifier promptly. Requires the `WEBHOOKS` scope and the `manage_settings` org permission.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The endpoint id to rotate.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "The new signing secret. Returned only once.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookSecretResponse" } } } }, "400": { "description": "Invalid endpoint id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Endpoint not found or not owned by your organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/webhooks/{id}/deliveries": { "get": { "operationId": "webhooks_list_deliveries", "tags": [ "webhooks" ], "summary": "List delivery attempts", "description": "Returns recent delivery attempts for an endpoint, newest first. Each row updates in place across retries, so an event that retried several times appears as one record whose `attempt_count` and `status` reflect the latest state. This endpoint does NOT use the `data` + `pagination` cursor envelope; it returns a `deliveries` array bounded by `limit`. Requires the `WEBHOOKS` scope and the `manage_settings` org permission.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The endpoint id whose deliveries to list.", "schema": { "type": "string", "format": "uuid" } }, { "name": "limit", "in": "query", "required": false, "description": "Max rows to return. Between 1 and 200. Defaults to 50. Out-of-range values return 400.", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } } ], "responses": { "200": { "description": "Recent delivery attempts for the endpoint.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookDeliveryList" } } } }, "400": { "description": "Invalid endpoint id or a limit outside 1 to 200.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Endpoint not found or not owned by your organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/analytics/dashboard": { "get": { "operationId": "analytics_dashboard", "tags": [ "analytics" ], "summary": "Get dashboard analytics", "description": "Org-wide dashboard overview: aggregate stats, recent activity, top campaigns, account health, and a daily trend series.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "period", "in": "query", "required": false, "description": "One of 7d, 30d, 90d. Any other value falls back to 7d.", "schema": { "type": "string", "enum": [ "7d", "30d", "90d" ], "default": "7d" } } ], "responses": { "200": { "description": "Dashboard analytics overview.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DashboardAnalytics" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/analytics/deliverability": { "get": { "operationId": "analytics_deliverability", "tags": [ "analytics" ], "summary": "Get deliverability dashboard", "description": "Deliverability posture over a window: bounce/complaint/open/click/reply counts and rates, suppression and dead-letter pressure, reply-intent breakdown, seed inbox-placement, health band, daily timeseries, and per-mailbox/per-campaign breakdowns.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "from", "in": "query", "required": false, "description": "Window start as an RFC 3339 timestamp. Defaults to 7 days ago (UTC).", "schema": { "type": "string", "format": "date-time" } }, { "name": "to", "in": "query", "required": false, "description": "Window end as an RFC 3339 timestamp. Defaults to now (UTC).", "schema": { "type": "string", "format": "date-time" } } ], "responses": { "200": { "description": "Deliverability dashboard.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeliverabilityDashboard" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/analytics/warmup": { "get": { "operationId": "analytics_warmup", "tags": [ "analytics" ], "summary": "Get warmup analytics", "description": "Warmup send and reply statistics over a date range, with a summary and per-day series. Optionally scoped to a single mailbox.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "from", "in": "query", "required": true, "description": "Range start (YYYY-MM-DD).", "schema": { "type": "string", "format": "date" } }, { "name": "to", "in": "query", "required": true, "description": "Range end (YYYY-MM-DD).", "schema": { "type": "string", "format": "date" } }, { "name": "email_id", "in": "query", "required": false, "description": "Limit to one email account. Invalid UUIDs are ignored.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Warmup analytics.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WarmupAnalytics" } } } }, "400": { "description": "Missing or invalid range.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/analytics/warmup/placement": { "get": { "operationId": "analytics_warmup_placement", "tags": [ "analytics" ], "summary": "Get warmup placement", "description": "Where warmup mail landed in partners' mailboxes (inbox, Gmail category tab, spam) per UTC day, per recipient provider and, for the workspace, per mailbox, plus the trailing 7-day inbox rate. Requires an organization context.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "from", "in": "query", "required": false, "description": "Range start (YYYY-MM-DD). Defaults to 29 days before to.", "schema": { "type": "string", "format": "date" } }, { "name": "to", "in": "query", "required": false, "description": "Range end (YYYY-MM-DD). Defaults to today (UTC).", "schema": { "type": "string", "format": "date" } }, { "name": "email_id", "in": "query", "required": false, "description": "Limit to one email account in the workspace. Omit for the workspace report.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Warmup placement report.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WarmupPlacementReport" } } } }, "400": { "description": "Invalid range, date or email_id, or a range longer than 366 days.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "The email account is not in the workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/placement/overview": { "get": { "operationId": "placement_overview", "tags": [ "placement" ], "summary": "Get the placement overview", "description": "The seed panels this workspace can test on, each with its seed count and provider mix, and the workspace's monthly allowance. Scope READ_ANALYTICS, org permission view_analytics.", "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Panels and allowance.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PlacementOverview" } } } } } }, "400": { "description": "No organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/placement/tests": { "get": { "operationId": "placement_tests_list", "tags": [ "placement" ], "summary": "List placement tests", "description": "The workspace's placement tests, newest first, with where their copies landed overall and per provider family. Bodies are left out. Scope READ_ANALYTICS, org permission view_analytics.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "limit", "in": "query", "required": false, "description": "Page size, 1 to 100. Default 25.", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from a previous pagination.next_cursor.", "schema": { "type": "string" } }, { "name": "campaign_id", "in": "query", "required": false, "description": "Only tests of this campaign.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "A page of tests.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data", "pagination" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/PlacementTest" } }, "pagination": { "$ref": "#/components/schemas/Pagination" } } } } } }, "400": { "description": "Invalid cursor, limit or campaign_id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "placement_tests_create", "tags": [ "placement" ], "summary": "Start a placement test", "description": "Send a template or a campaign step from one of the workspace's mailboxes to a seed panel, one copy per seed, each a send charged to the mailbox's daily limit. A tracking comparison starts two linked tests. Every check runs before anything is scheduled, so a refused request sends nothing. Scope SEND_CAMPAIGNS, org permission send_campaigns.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreatePlacementTestRequest" } } } }, "responses": { "201": { "description": "The new test, or two sharing a compare_group_id for a tracking comparison.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/PlacementTest" } } } } } } }, "400": { "description": "Invalid body, panel or tracking; a sequence_id without campaign_id; seed_ids without panel workspace; no subject or body; placement_invalid_tracking; or placement_invalid_seeds.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "402": { "description": "placement_not_entitled (no active trial or subscription), placement_quota_exceeded (the month's free tests are used and max_credits is missing or below the price, or the test cannot be paid for), or insufficient_credits.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions, or an API key that may not use the sending mailbox.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "The sending mailbox, campaign, step or contact is not in the workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "placement_sender_busy, placement_sender_unavailable, placement_daily_budget, placement_no_seeds or placement_panel_unavailable.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "placement_too_many_running (3 tests in flight per workspace), usage_cap_exceeded (a paid test past a credit spend limit), or rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Warmbly Cloud did not open the test.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/placement/tests/{id}": { "get": { "operationId": "placement_tests_get", "tags": [ "placement" ], "summary": "Get a placement test", "description": "One test with its copy, every seed's result, the content check of the copy and, for a tracking comparison, the other half. Seed addresses are masked on the instance and cloud panels. Scope READ_ANALYTICS, org permission view_analytics.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Placement test id.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The test.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PlacementTestDetail" } } } } } }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/placement/tests/{id}/cancel": { "post": { "operationId": "placement_tests_cancel", "tags": [ "placement" ], "summary": "Cancel a placement test", "description": "Stop the copies not yet sent. Copies already sent keep being classified. Scope SEND_CAMPAIGNS, org permission send_campaigns.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Placement test id.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "The cancelled test.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PlacementTest" } } } } } }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "placement_not_running: the test already finished.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/placement/batches": { "get": { "operationId": "placement_batches_list", "tags": [ "placement" ], "summary": "List placement batches", "description": "The workspace's placement batches, newest first, with progress and headline placement. Scope READ_ANALYTICS, org permission view_analytics.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "limit", "in": "query", "required": false, "description": "Page size, 1 to 100. Default 25.", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from a previous pagination.next_cursor.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "A page of batches.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data", "pagination" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/PlacementBatch" } }, "pagination": { "$ref": "#/components/schemas/Pagination" } } } } } }, "400": { "description": "Invalid cursor or limit.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "placement_batches_create", "tags": [ "placement" ], "summary": "Start a placement batch", "description": "Run the same placement test from many sending mailboxes, chosen by id or resolved on the server from a campaign or the whole workspace, optionally sampled. The senders are written down and the batch is answered queued; the backend starts them a few at a time, checking each mailbox's daily limit, connection and worker when its turn comes. Nothing is sent by the request. Scope SEND_CAMPAIGNS, org permission send_campaigns.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlacementBatchRequest" } } } }, "responses": { "201": { "description": "The queued batch.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PlacementBatch" } } } } } }, "400": { "description": "Malformed request, placement_batch_empty, placement_batch_too_large, placement_invalid_seeds or placement_invalid_tracking.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "402": { "description": "placement_not_entitled, placement_quota_exceeded or insufficient_credits.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions, or an API key naming a mailbox it may not use.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "A sending mailbox, campaign, step or contact is not in the workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "placement_no_seeds or placement_panel_unavailable.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited, or placement_too_many_batches.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/placement/batches/preview": { "post": { "operationId": "placement_batches_preview", "tags": [ "placement" ], "summary": "Preview a placement batch", "description": "What a batch request would come to: senders matched and selected, tests, the most copies sent, free and paid tests and credits. Writes and sends nothing. Scope SEND_CAMPAIGNS, org permission send_campaigns.", "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlacementBatchRequest" } } } }, "responses": { "200": { "description": "The counts.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PlacementBatchPreview" } } } } } }, "400": { "description": "Malformed request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "402": { "description": "placement_not_entitled.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "A sending mailbox, campaign, step or contact is not in the workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "placement_no_seeds or placement_panel_unavailable.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/placement/batches/{id}": { "get": { "operationId": "placement_batches_get", "tags": [ "placement" ], "summary": "Get a placement batch", "description": "One batch with its placement overall and grouped by sending domain, sending provider and recipient provider, worst first. Scope READ_ANALYTICS, org permission view_analytics.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Placement batch id.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The batch.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PlacementBatchDetail" } } } } } }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/placement/batches/{id}/senders": { "get": { "operationId": "placement_batches_senders", "tags": [ "placement" ], "summary": "List a placement batch's senders", "description": "The batch's mailboxes with where each one's copies landed and why any was deferred, skipped or failed. Scope READ_ANALYTICS, org permission view_analytics.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Placement batch id.", "schema": { "type": "string", "format": "uuid" } }, { "name": "limit", "in": "query", "required": false, "description": "Page size, 1 to 100. Default 25.", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from a previous pagination.next_cursor.", "schema": { "type": "string" } }, { "name": "sort", "in": "query", "required": false, "description": "worst (default, lowest inbox rate first), best, email or status.", "schema": { "type": "string", "enum": [ "worst", "best", "email", "status" ], "default": "worst" } }, { "name": "status", "in": "query", "required": false, "description": "Only mailboxes in this status.", "schema": { "type": "string", "enum": [ "queued", "deferred", "running", "completed", "skipped", "failed", "cancelled" ] } }, { "name": "q", "in": "query", "required": false, "description": "Only addresses containing this text.", "schema": { "type": "string", "maxLength": 200 } } ], "responses": { "200": { "description": "A page of senders.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data", "pagination" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/PlacementBatchSender" } }, "pagination": { "$ref": "#/components/schemas/Pagination" } } } } } }, "400": { "description": "Invalid id, cursor, limit, sort or status.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/placement/batches/{id}/cancel": { "post": { "operationId": "placement_batches_cancel", "tags": [ "placement" ], "summary": "Cancel a placement batch", "description": "Stop the batch: no mailbox starts again, copies not sent yet are cancelled, copies already sent keep being classified. Scope SEND_CAMPAIGNS, org permission send_campaigns.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Placement batch id.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "The cancelled batch.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PlacementBatch" } } } } } }, "400": { "description": "Invalid id.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "placement_batch_not_running.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/placement/coverage": { "get": { "operationId": "placement_coverage", "tags": [ "placement" ], "summary": "Get placement fleet coverage", "description": "How many of the workspace's connected sending mailboxes finished a placement test in the last 7 and 30 days, and how many never did. Scope READ_ANALYTICS, org permission view_analytics.", "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The coverage.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PlacementCoverage" } } } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/placement/seeds": { "get": { "operationId": "placement_seeds_list", "tags": [ "placement" ], "summary": "List seed inboxes", "description": "Every mailbox of the workspace with whether it is one of its seed inboxes, and why it cannot become one when it cannot. An API key restricted to certain mailboxes sees only those. Scope READ_EMAILS, org permission view_campaigns.", "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The workspace's mailboxes.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/PlacementWorkspaceSeed" } } } } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/placement/seeds/{email_account_id}": { "put": { "operationId": "placement_seeds_set", "tags": [ "placement" ], "summary": "Mark a seed inbox", "description": "Make a workspace mailbox one of its seed inboxes, or an ordinary mailbox again. A seed never warms up (its warmup is turned off here), never sends campaign mail and cannot send a placement test. The body states the value to hold, so a retry lands on the same state. Scope WRITE_EMAILS, org permission manage_emails.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "email_account_id", "in": "path", "required": true, "description": "The mailbox id.", "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetPlacementSeedRequest" } } } }, "responses": { "200": { "description": "The mailbox.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PlacementWorkspaceSeed" } } } } } }, "400": { "description": "Invalid id, or seed missing.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "The mailbox is not in the workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "placement_seed_unavailable (on the instance panel, or a test is sending from it) or placement_seed_limit (50 per workspace).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/analytics/campaigns/compare": { "get": { "operationId": "analytics_campaigns_compare", "tags": [ "analytics" ], "summary": "Compare campaigns", "description": "Side-by-side performance for up to 10 campaigns over a date range. Every requested campaign must belong to the caller.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "ids", "in": "query", "required": true, "description": "Comma-separated campaign UUIDs. Invalid entries are dropped; capped at 10. At least one valid id is required.", "schema": { "type": "string" } }, { "name": "from", "in": "query", "required": true, "description": "First day (YYYY-MM-DD, UTC).", "schema": { "type": "string", "format": "date" } }, { "name": "to", "in": "query", "required": true, "description": "Last day (YYYY-MM-DD, UTC), included.", "schema": { "type": "string", "format": "date" } } ], "responses": { "200": { "description": "Campaign comparison.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignComparison" } } } }, "400": { "description": "Missing or invalid ids/range.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "A requested campaign was not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/analytics/campaigns/{id}": { "get": { "operationId": "analytics_campaign_get", "tags": [ "analytics" ], "summary": "Get campaign analytics", "description": "A single campaign's performance summary plus per-step stats, for its whole history or for the emails sent from `from` to `to`. A period is a send cohort: the emails sent on its UTC days, with every open, click, reply and bounce they earned whenever it arrived. total_contacts and emails_pending are the campaign's current state whatever the period. The campaign must belong to the caller.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Campaign id.", "schema": { "type": "string", "format": "uuid" } }, { "name": "from", "in": "query", "required": false, "description": "First day of the period (YYYY-MM-DD, UTC). Requires to; omit both for all time.", "schema": { "type": "string", "format": "date" } }, { "name": "to", "in": "query", "required": false, "description": "Last day of the period (YYYY-MM-DD, UTC), included. Requires from.", "schema": { "type": "string", "format": "date" } } ], "responses": { "200": { "description": "Campaign analytics.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignAnalytics" } } } }, "400": { "description": "Only one of from and to, a malformed date, or from after to.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Campaign not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/analytics/campaigns/{id}/daily": { "get": { "operationId": "analytics_campaign_daily", "tags": [ "analytics" ], "summary": "Get campaign daily stats", "description": "Per-day send, open, click, and reply counts for one campaign over a date range. The campaign must belong to the caller.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Campaign id.", "schema": { "type": "string", "format": "uuid" } }, { "name": "from", "in": "query", "required": true, "description": "First day (YYYY-MM-DD, UTC).", "schema": { "type": "string", "format": "date" } }, { "name": "to", "in": "query", "required": true, "description": "Last day (YYYY-MM-DD, UTC), included.", "schema": { "type": "string", "format": "date" } } ], "responses": { "200": { "description": "Per-day series under a data envelope.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignDailyStats" } } } }, "400": { "description": "Missing or invalid range.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Campaign not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/analytics/campaigns/{id}/hourly": { "get": { "operationId": "analytics_campaign_hourly", "tags": [ "analytics" ], "summary": "Get campaign hourly stats", "description": "Per-hour stats for one campaign on a single day. The campaign must belong to the caller.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Campaign id.", "schema": { "type": "string", "format": "uuid" } }, { "name": "date", "in": "query", "required": false, "description": "Day to report (YYYY-MM-DD). Defaults to today.", "schema": { "type": "string", "format": "date" } } ], "responses": { "200": { "description": "Per-hour series under a data envelope with the resolved date echoed back.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CampaignHourlyStats" } } } }, "400": { "description": "Invalid date.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Campaign not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/analytics/accounts": { "get": { "operationId": "analytics_accounts_list", "tags": [ "analytics" ], "summary": "List account statuses", "description": "Health and usage status of every email account the caller owns. Returned under a data envelope (no cursor; all accounts included). Accounts that fail to build are skipped.", "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Account statuses.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountStatusList" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/analytics/accounts/{id}": { "get": { "operationId": "analytics_account_get", "tags": [ "analytics" ], "summary": "Get account status", "description": "Detailed status for one email account: combined health score (folding in warmup-pool reputation), active errors, today's usage, warmup status, and warmup-pool health. The account must belong to the caller.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Email account id.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Account status detail.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountStatusDetail" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Account not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/analytics/usage": { "get": { "operationId": "analytics_usage", "tags": [ "analytics" ], "summary": "Get usage overview", "description": "Account, campaign, contact, and API usage counters for the caller.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "period", "in": "query", "required": false, "description": "One of day, week, month. Any other value falls back to day.", "schema": { "type": "string", "enum": [ "day", "week", "month" ], "default": "day" } } ], "responses": { "200": { "description": "Usage overview.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UsageOverview" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/audit-logs": { "get": { "operationId": "analytics_audit_logs_list", "tags": [ "analytics" ], "summary": "List audit logs", "description": "Organization-wide activity trail for the caller's current organization. The organization is always taken from the session, never from a parameter. Auth: scope READ_AUDIT_LOGS, org permission view_analytics.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "limit", "in": "query", "required": false, "description": "Page size. Defaults to 50; must be between 10 and 200 or a 400 is returned.", "schema": { "type": "integer", "minimum": 10, "maximum": 200, "default": 50 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from pagination.next_cursor. Invalid cursors return 400.", "schema": { "type": "string" } }, { "name": "actor_id", "in": "query", "required": false, "description": "Filter to a single acting member.", "schema": { "type": "string", "format": "uuid" } }, { "name": "entity_id", "in": "query", "required": false, "description": "Filter to a single entity.", "schema": { "type": "string", "format": "uuid" } }, { "name": "entity_type", "in": "query", "required": false, "description": "Filter by entity type (for example campaign, contact, email_account, api_key, webhook).", "schema": { "type": "string" } }, { "name": "action", "in": "query", "required": false, "description": "Filter by action (for example create, update, delete, send, revoke).", "schema": { "type": "string" } }, { "name": "date", "in": "query", "required": false, "description": "Single-day filter (YYYY-MM-DD), expanded to that whole UTC day.", "schema": { "type": "string", "format": "date" } }, { "name": "start_date", "in": "query", "required": false, "description": "Range start. RFC 3339 or YYYY-MM-DD. Overrides date.", "schema": { "type": "string" } }, { "name": "end_date", "in": "query", "required": false, "description": "Range end. RFC 3339 or YYYY-MM-DD. Overrides date.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Audit log page (data plus pagination).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuditLogList" } } } }, "400": { "description": "Invalid cursor, limit, or filter.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient permissions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/integrations/catalog": { "get": { "operationId": "integrations_catalog_list", "summary": "List the integration catalog", "description": "Static metadata for every provider Warmbly supports, annotated with whether each OAuth provider has server-side credentials wired (`configured`).", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Provider catalog.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationCatalogList" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden (missing INTEGRATIONS scope).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/integrations/connections": { "get": { "operationId": "integrations_connections_list", "summary": "List connections", "description": "This org's connection rows. Secrets are never serialized. Returns a bare `connections` array, not the cursor-paginated envelope.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Connections.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationConnectionList" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "integrations_connections_create", "summary": "Create a connection", "description": "Creates a credential-based connection for `api_key` / `webhook` providers (e.g. Close, Discord). OAuth providers are rejected with a hint to start the authorize flow instead. Inbound providers (Calendly, Cal.com) include `inbound_webhook_url` once. Requires the `manage_settings` org permission for JWT callers.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationConnectionCreate" } } } }, "responses": { "201": { "description": "Connection created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationConnection" } } } }, "400": { "description": "Bad request (e.g. OAuth provider, invalid provider).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden (paid-plan feature or missing permission).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/integrations/connections/{id}": { "get": { "operationId": "integrations_connections_get", "summary": "Get a connection", "description": "One connection plus its event subscriptions and up to 20 recent sync runs.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." } ], "responses": { "200": { "description": "Connection detail.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationConnectionDetail" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "integrations_connections_delete", "summary": "Disconnect", "description": "Removes a connection row. Requires `manage_settings` for JWT callers.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Disconnected." }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/integrations/connections/{id}/config": { "patch": { "operationId": "integrations_connections_update_config", "summary": "Update connection config", "description": "Saves a connection's onboarding/capability snapshot and its sync direction. Requires `manage_settings` for JWT callers.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationConnectionConfigUpdate" } } } }, "responses": { "200": { "description": "Updated connection.", "content": { "application/json": { "schema": { "type": "object", "required": [ "connection" ], "properties": { "connection": { "$ref": "#/components/schemas/IntegrationConnection" } } } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/integrations/connections/{id}/events": { "get": { "operationId": "integrations_event_subscriptions_list", "summary": "List event subscriptions", "description": "The event-to-action routes configured on a connection.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." } ], "responses": { "200": { "description": "Event subscriptions.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationEventSubscriptionList" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "integrations_event_subscriptions_create", "summary": "Create an event subscription", "description": "Routes a Warmbly event to a provider action on this connection. Requires `manage_settings` for JWT callers.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationEventSubscriptionCreate" } } } }, "responses": { "201": { "description": "Event subscription created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationEventSubscription" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden (paid-plan feature or missing permission).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/integrations/connections/{id}/events/{eventId}": { "delete": { "operationId": "integrations_event_subscriptions_delete", "summary": "Delete an event subscription", "description": "Removes one event subscription. Requires `manage_settings` for JWT callers.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." }, { "name": "eventId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Event subscription id." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Deleted." }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/integrations/connections/{id}/field-mappings": { "get": { "operationId": "integrations_field_mappings_list", "summary": "List field mappings", "description": "The Warmbly-field to provider-field maps configured for a connection.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." } ], "responses": { "200": { "description": "Field mappings.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationFieldMappingList" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "put": { "operationId": "integrations_field_mappings_replace", "summary": "Replace field mappings", "description": "Swaps the connection-default field map for an object wholesale. A full replace is naturally idempotent so no `Idempotency-Key` is required. Requires `manage_settings` for JWT callers.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationFieldMappingReplace" } } } }, "responses": { "200": { "description": "Full mapping set after the replace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationFieldMappingList" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/integrations/connections/{id}/runs": { "get": { "operationId": "integrations_sync_runs_list", "summary": "List sync runs", "description": "Up to 50 recent observability records for a connection (connect, token refresh, event dispatch, manual push).", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." } ], "responses": { "200": { "description": "Sync runs.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationSyncRunList" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/integrations/connections/{id}/signing-key": { "put": { "operationId": "integrations_connections_set_signing_key", "summary": "Set the inbound signing key", "description": "Sets the key a Calendly or Cal.com connection's inbound deliveries must be signed with (Calendly's `Calendly-Webhook-Signature`, Cal.com's `X-Cal-Signature-256`). Once set, a delivery without a valid signature is refused with `401`. An empty `signing_key` removes it, so the inbound URL alone authenticates deliveries again. The key is stored encrypted and never returned; `display_fields.inbound_signing` reports whether one is set. Requires `manage_settings` for JWT callers.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationSigningKeyUpdate" } } } }, "responses": { "200": { "description": "Updated connection.", "content": { "application/json": { "schema": { "type": "object", "required": [ "connection" ], "properties": { "connection": { "$ref": "#/components/schemas/IntegrationConnection" } } } } } }, "400": { "description": "Bad request: the connection is not a Calendly or Cal.com connection, or `signing_key` is 1 to 7 characters or longer than 512. An empty `signing_key` is accepted and removes the key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/integrations/connections/{id}/rotate-inbound-url": { "post": { "operationId": "integrations_connections_rotate_inbound_url", "summary": "Rotate the inbound webhook URL", "description": "Mints a new inbound webhook URL for a Calendly or Cal.com connection. The previous URL stops working immediately, so paste the new one into the provider. Requires `manage_settings` for JWT callers.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "The new inbound URL.", "content": { "application/json": { "schema": { "type": "object", "required": [ "inbound_webhook_url" ], "properties": { "inbound_webhook_url": { "type": "string", "description": "Path of the new inbound URL, relative to the API host." } } } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/integrations/connections/{id}/webhook-secret": { "get": { "operationId": "integrations_webhook_secret_get", "summary": "Get the connection webhook secret", "description": "Returns (generating on first call) the HMAC signing secret for an automation connection so you can verify Warmbly's outbound webhook signatures. Requires `manage_settings` for JWT callers.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." } ], "responses": { "200": { "description": "Signing secret.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationWebhookSecret" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/integrations/connections/{id}/test": { "post": { "operationId": "integrations_connection_test", "summary": "Test a connection", "description": "Fires a synthetic event through the connection's notify/webhook automations so you can confirm the channel is wired. Requires `manage_settings` for JWT callers.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "Test event dispatched.", "content": { "application/json": { "schema": { "type": "object", "required": [ "sent" ], "properties": { "sent": { "type": "boolean" } } } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/integrations/connections/{id}/push": { "post": { "operationId": "integrations_connection_push", "summary": "Push contacts to a CRM", "description": "Synchronously upserts the given org contacts into a connected CRM (HubSpot, Pipedrive, Salesforce, Close). Retries are naturally safe (every upsert is keyed by email), so no `Idempotency-Key` is required. Requires the `use_integrations` org permission for JWT callers. A connection whose token can no longer be refreshed returns 409.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationPushRequest" } } } }, "responses": { "200": { "description": "Per-record push results.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IntegrationPushResult" } } } }, "400": { "description": "A selection that names nothing, an exclusion list over 250000 or one resolving to more than 500 contacts (`too_many_contacts`), a select-all with no filters, a filter matching no contacts, or a filter matching more than 250000 (`selection_too_large`).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden (paid-plan feature or missing permission).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Connection or matching contacts not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Connection needs to be reconnected (token not refreshable).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/integrations/bookings": { "get": { "operationId": "integrations_bookings_list", "summary": "List meeting bookings (integrations view)", "description": "Up to 50 recent booked meetings, surfaced on the integrations page. For the full Meetings list with filters and pagination, use `GET /meetings`.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Recent bookings.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MeetingBookingList" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/automations": { "get": { "operationId": "automations_list", "summary": "List automations", "description": "This org's automation flows (the visual flow builder). Returns a bare `automations` array.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Automations.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AutomationList" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "automations_create", "summary": "Create an automation", "description": "Creates a new automation flow: a trigger event plus a graph of condition and action nodes. Action nodes may reference provider actions (e.g. `slack.notify`, `hubspot.upsert_contact`) or Warmbly-native actions (e.g. `warmbly.add_tag`, `warmbly.label_email`) that need no external connection.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AutomationWrite" } } } }, "responses": { "201": { "description": "Automation created.", "content": { "application/json": { "schema": { "type": "object", "required": [ "automation" ], "properties": { "automation": { "$ref": "#/components/schemas/Automation" } } } } } }, "400": { "description": "Bad request (invalid graph, missing trigger).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden (paid-plan feature or missing permission).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/automations/{id}": { "get": { "operationId": "automations_get", "summary": "Get an automation", "description": "One automation with its full graph.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Automation id." } ], "responses": { "200": { "description": "Automation.", "content": { "application/json": { "schema": { "type": "object", "required": [ "automation" ], "properties": { "automation": { "$ref": "#/components/schemas/Automation" } } } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "automations_update", "summary": "Update an automation", "description": "Replaces an automation's name, enabled state, trigger, filter, and graph. The body shape matches the create payload.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Automation id." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AutomationWrite" } } } }, "responses": { "200": { "description": "Updated automation.", "content": { "application/json": { "schema": { "type": "object", "required": [ "automation" ], "properties": { "automation": { "$ref": "#/components/schemas/Automation" } } } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "automations_delete", "summary": "Delete an automation", "description": "Removes an automation. Returns 409 when the automation is still referenced by campaign steps.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Automation id." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "Deleted.", "content": { "application/json": { "schema": { "type": "object", "required": [ "deleted" ], "properties": { "deleted": { "type": "boolean" } } } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Still referenced by campaign steps.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/automations/{id}/test": { "post": { "operationId": "automations_test", "summary": "Test an automation", "description": "Runs the automation against sample (or provided) data without side effects and returns the walked trace plus per-action previews.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Automation id." }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AutomationDryRunRequest" } } } }, "responses": { "200": { "description": "Dry-run trace plus resolved event data.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AutomationDryRunResponse" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/automations/{id}/runs": { "get": { "operationId": "automations_runs_list", "summary": "List automation runs", "description": "Recent run history for an automation (per fired event or manual launch), with per-node outcomes.", "tags": [ "integrations" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Automation id." }, { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "default": 50 }, "description": "Max runs to return. Defaults to 50." } ], "responses": { "200": { "description": "Automation runs.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AutomationRunList" } } } }, "400": { "description": "Bad request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/teams": { "get": { "operationId": "account-org_teams_list", "summary": "List teams", "description": "Returns the current organization's teams, each hydrated with its members. Requires a selected organization.", "tags": [ "account-org" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The organization's teams.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamCollection" } } } }, "400": { "description": "No organization selected or invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Key lacks the READ_CRM scope or caller lacks view_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "account-org_teams_create", "summary": "Create a team", "description": "Creates a team (members start empty). Requires a selected organization.", "tags": [ "account-org" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamCreate" } } } }, "responses": { "201": { "description": "The created team.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Team" } } } }, "400": { "description": "Validation error or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Key lacks the WRITE_CRM scope or caller lacks manage_team.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/teams/{id}": { "get": { "operationId": "account-org_teams_get", "summary": "Get a team", "description": "Returns a single team with its members.", "tags": [ "account-org" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The team id.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The team.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Team" } } } }, "400": { "description": "Invalid id or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Key lacks the READ_CRM scope or caller lacks view_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Team not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "account-org_teams_update", "summary": "Update a team", "description": "Partial-updates a team's name or color. Omitted fields are left untouched.", "tags": [ "account-org" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The team id.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamUpdate" } } } }, "responses": { "200": { "description": "The updated team.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Team" } } } }, "400": { "description": "Validation error, invalid id, or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Key lacks the WRITE_CRM scope or caller lacks manage_team.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Team not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "account-org_teams_delete", "summary": "Delete a team", "description": "Deletes a team.", "tags": [ "account-org" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The team id.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Team deleted." }, "400": { "description": "Invalid id or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Key lacks the WRITE_CRM scope or caller lacks manage_team.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Team not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/teams/{id}/members": { "post": { "operationId": "account-org_teams_add_member", "summary": "Add a team member", "description": "Adds an existing organization member to the team and returns the updated team.", "tags": [ "account-org" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The team id.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamAddMember" } } } }, "responses": { "200": { "description": "The updated team, including the new member.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Team" } } } }, "400": { "description": "Validation error, invalid id, or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Key lacks the WRITE_CRM scope or caller lacks manage_team.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Team not found, or the user is not an organization member.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/teams/{id}/members/{userId}": { "delete": { "operationId": "account-org_teams_remove_member", "summary": "Remove a team member", "description": "Removes a member from the team.", "tags": [ "account-org" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The team id.", "schema": { "type": "string", "format": "uuid" } }, { "name": "userId", "in": "path", "required": true, "description": "The member's user id.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Member removed." }, "400": { "description": "Invalid id or no organization selected.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Key lacks the WRITE_CRM scope or caller lacks manage_team.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Team or membership not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/plans": { "get": { "operationId": "account-org_plans_list", "summary": "List plans", "description": "Returns the available public subscription plans. Open to any authenticated caller (JWT or API key); auth exists only to deter scraping.", "tags": [ "account-org" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The public subscription plans.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlanList" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/timezones": { "get": { "operationId": "account-org_timezones_list", "summary": "List timezones", "description": "Returns the supported timezone identifiers (for campaign schedule windows and the like). Open to any authenticated caller (JWT or API key).", "tags": [ "account-org" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The supported timezones, sorted by UTC offset.", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/TimezoneOption" } } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/outreach/settings": { "get": { "operationId": "deliverability-ops_get_settings", "summary": "Get outreach settings", "description": "Returns the organization's advanced outreach settings (bounce pipeline, task reliability, A/B testing, reply-intent, send-time optimization, preflight, dashboard).", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The advanced outreach settings object (not envelope-wrapped).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdvancedOutreachSettings" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden (missing WRITE_CAMPAIGNS scope or manage_settings permission)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "deliverability-ops_update_settings", "summary": "Update outreach settings", "description": "Replaces the organization's advanced outreach settings with the supplied object (upserted, not deep-merged). A field the object omits takes its default, not its previous value. Returns no body.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpsertOutreachSettingsRequest" } } } }, "responses": { "204": { "description": "Settings updated" }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/deliverability/events": { "post": { "operationId": "deliverability-ops_ingest_event", "summary": "Ingest a deliverability event", "description": "Posts a single deliverability signal (bounce, complaint, unsubscribe, open, click, reply) into the platform. API-key callable so downstream pipelines can report events. Supply idempotency_key to make retries safe. Requires WRITE_CAMPAIGNS scope and send_campaigns permission.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IngestDeliverabilityEventRequest" } } } }, "responses": { "202": { "description": "Event accepted and queued for processing (no body)." }, "400": { "description": "Invalid event payload (e.g. missing event_type or recipient_email)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tasks/dlq": { "get": { "operationId": "deliverability-ops_list_dead_letters", "summary": "List task dead letters", "description": "Lists tasks that exhausted their retry budget and landed in the dead-letter queue. Not cursor-paginated: returns up to `limit` rows in one response. Requires SEND_CAMPAIGNS scope and send_campaigns permission.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "status", "in": "query", "required": false, "description": "Optional status filter (e.g. pending, replayed).", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "required": false, "description": "Max rows to return, 1 to 200 (default 100).", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 100 } } ], "responses": { "200": { "description": "Dead-letter records under a `data` array.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TaskDeadLetterList" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tasks/dlq/{id}/replay": { "post": { "operationId": "deliverability-ops_replay_dead_letter", "summary": "Replay a task dead letter", "description": "Re-dispatches a dead-lettered task. Because a replay can transmit real mail this requires SEND_CAMPAIGNS scope and send_campaigns permission.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The dead-letter record ID (the `id` field, not `task_id`).", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "Replay dispatched.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReplayDeadLetterResponse" } } } }, "400": { "description": "Invalid dead-letter id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Dead-letter record not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/warmup/routing": { "get": { "operationId": "deliverability-ops_list_routing_rules", "summary": "List warmup routing rules", "description": "Returns every warmup routing rule for the organization, ordered by priority ascending. Not cursor-paginated. Requires WARMUP_ROUTING scope and manage_settings permission.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Routing rules under a `rules` array (never null).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WarmupRoutingRuleList" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "deliverability-ops_create_routing_rule", "summary": "Create a warmup routing rule", "description": "Creates a routing rule for the organization. Both sender and recipient sides are matched; a rule applies only when both match. Match values are lowercased and trimmed on write. Requires WARMUP_ROUTING scope and manage_settings permission.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WarmupRoutingRuleInput" } } } }, "responses": { "201": { "description": "Rule created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WarmupRoutingRule" } } } }, "400": { "description": "Invalid payload (e.g. missing name, bad match type, missing required match value, negative weight)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/warmup/routing/{id}": { "patch": { "operationId": "deliverability-ops_update_routing_rule", "summary": "Update a warmup routing rule", "description": "Replaces a rule by ID. The body is the same full payload as create (all fields applied, not deep-merged). Requires WARMUP_ROUTING scope and manage_settings permission.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The rule ID.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WarmupRoutingRuleInput" } } } }, "responses": { "200": { "description": "Rule updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WarmupRoutingRule" } } } }, "400": { "description": "Invalid payload or rule id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Rule not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "deliverability-ops_delete_routing_rule", "summary": "Delete a warmup routing rule", "description": "Removes a routing rule by ID. Requires WARMUP_ROUTING scope and manage_settings permission.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The rule ID.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Rule deleted" }, "400": { "description": "Invalid rule id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Rule not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/templates": { "get": { "operationId": "deliverability-ops_list_templates", "summary": "List reply templates", "description": "Lists the organization's reply templates, ordered by position. Optional `q` filter matches name and subject (case-insensitive). Not cursor-paginated. Requires READ_TEMPLATES scope and view_campaigns permission.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "q", "in": "query", "required": false, "description": "Optional case-insensitive search over name and subject.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Reply templates under a `data` array.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReplyTemplateList" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "deliverability-ops_create_template", "summary": "Create a reply template", "description": "Creates a reply template owned by the calling user, appended to the end of the org's list. Requires WRITE_TEMPLATES scope and manage_campaigns permission.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateReplyTemplate" } } } }, "responses": { "200": { "description": "Template created.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReplyTemplate" } } } }, "400": { "description": "Invalid payload (e.g. missing name or name over 255 chars)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/templates/reorder": { "patch": { "operationId": "deliverability-ops_reorder_templates", "summary": "Reorder reply templates", "description": "Repositions templates to match the supplied ID order (1-indexed). IDs omitted from the list are left untouched. Returns the full reordered list. Requires WRITE_TEMPLATES scope and manage_campaigns permission.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReorderReplyTemplates" } } } }, "responses": { "200": { "description": "Reordered list under a `data` array.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReplyTemplateList" } } } }, "400": { "description": "Invalid payload (e.g. missing ids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/templates/analyze": { "post": { "operationId": "deliverability-ops_analyze_template", "summary": "Analyze template content with AI", "description": "Runs the deployment's configured AI provider over a subject and body and returns the specific words and sentences that hurt deliverability, quoted from the copy, with whether each one is in the subject or the body and what to write instead. The rules-based score runs in the same request and comes back under `rules`. Advisory only and never blocks sending. Spends AI credits; honors `Idempotency-Key`. Requires WRITE_TEMPLATES scope (it writes no template, but a read-only key must not be able to spend the workspace credits), and the view_campaigns and use_ai permissions.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "Idempotency-Key", "in": "header", "required": false, "description": "Makes a retry safe: the same key is never charged twice.", "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScoreTemplateRequest" } } } }, "responses": { "200": { "description": "The analysis, with the rules-based pass alongside it.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TemplateAnalysis" } } } }, "400": { "description": "Nothing written to analyze, or the template is over the size cap", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "402": { "description": "Out of AI credits. Nothing is charged and no provider call is made.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "No AI provider configured (code `ai_not_configured`, permanent for that deployment), or the provider failed (code `service_unavailable`, and the reserved credits are refunded).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/templates/score": { "post": { "operationId": "deliverability-ops_score_template", "summary": "Score template content", "description": "Returns an advisory deliverability content score (0 to 100, higher is safer) for a subject and body, plus the issues found. Advisory only and never blocks sending. Scores content in the request body, not a stored template. Requires READ_TEMPLATES scope and view_campaigns permission.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScoreTemplateRequest" } } } }, "responses": { "200": { "description": "Content score and advisory issues.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TemplateScoreResult" } } } }, "400": { "description": "Invalid request body", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/templates/{id}": { "get": { "operationId": "deliverability-ops_get_template", "summary": "Get a reply template", "description": "Retrieves a single reply template by ID. Requires READ_TEMPLATES scope and view_campaigns permission.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The template ID.", "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The reply template.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReplyTemplate" } } } }, "400": { "description": "Invalid template id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Template not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "operationId": "deliverability-ops_update_template", "summary": "Update a reply template", "description": "Updates a reply template. All fields optional; omitted fields are left unchanged. Requires WRITE_TEMPLATES scope and manage_campaigns permission.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The template ID.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateReplyTemplate" } } } }, "responses": { "200": { "description": "Template updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReplyTemplate" } } } }, "400": { "description": "Invalid payload or template id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Template not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "deliverability-ops_delete_template", "summary": "Delete a reply template", "description": "Deletes a reply template by ID. Requires WRITE_TEMPLATES scope and manage_campaigns permission.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The template ID.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "204": { "description": "Template deleted" }, "400": { "description": "Invalid template id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Template not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/templates/{id}/duplicate": { "post": { "operationId": "deliverability-ops_duplicate_template", "summary": "Duplicate a reply template", "description": "Clones a template, appending \" (copy)\" to the name and placing the clone at the end of the org's list. Requires WRITE_TEMPLATES scope and manage_campaigns permission.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The source template ID.", "schema": { "type": "string", "format": "uuid" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "responses": { "200": { "description": "The newly created template.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReplyTemplate" } } } }, "400": { "description": "Invalid template id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Source template not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/templates/{id}/render": { "post": { "operationId": "deliverability-ops_render_template", "summary": "Render a reply template", "description": "Expands {{.Key}} placeholders in the template's subject and body using a caller-supplied variable map. The body is optional; an empty map renders all placeholders empty. Requires READ_TEMPLATES scope and view_campaigns permission.", "tags": [ "deliverability-ops" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The template ID.", "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RenderReplyTemplateRequest" } } } }, "responses": { "200": { "description": "The rendered subject and body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RenderedReplyTemplate" } } } }, "400": { "description": "Invalid template id or body", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Template not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/ai/tools": { "get": { "operationId": "ai_tools_list", "summary": "List agent tools", "description": "The AI tool registry filtered to what the caller's credentials allow. `format=openai` (aliases `hermes`, `functions`) returns OpenAI function-calling objects; the default returns `{name, description, input_schema}` per tool. Send-class tools are never listed.", "tags": [ "ai" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "format", "in": "query", "required": false, "description": "Manifest format.", "schema": { "type": "string", "enum": [ "warmbly", "openai", "hermes", "functions" ], "default": "warmbly" } } ], "responses": { "200": { "description": "The permitted tool catalog.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "type": "array", "items": { "type": "object", "description": "One tool, shaped by `format`." } } } } } } }, "400": { "description": "Unknown format, or no organization for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/ai/tools/{name}/call": { "post": { "operationId": "ai_tools_call", "summary": "Execute an agent tool", "description": "Runs one registry tool. The request body is the tool's JSON argument object (empty body = no arguments). Each tool enforces its own permission; send-class tools are never callable here.", "tags": [ "ai" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "The tool name from the list endpoint.", "schema": { "type": "string" } }, { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": false, "content": { "application/json": { "schema": { "type": "object", "description": "The tool's argument object, matching its input schema." } } } }, "responses": { "200": { "description": "The tool's output.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "type": "object", "required": [ "name", "result" ], "properties": { "name": { "type": "string" }, "result": { "description": "The tool's output, embedded as JSON when the tool returned JSON." } } } } } } } }, "400": { "description": "Malformed argument body, or no organization for this key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The credentials lack the permission for this tool.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Unknown tool.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Tool-level failure; the message is meant for the model to read.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/suppressions": { "get": { "tags": [ "deliverability-ops" ], "operationId": "deliverability-ops_list_suppressions", "summary": "List the suppression list", "description": "Pages the workspace suppression list newest first: every address and domain no campaign will email. Scope `READ_CONTACTS`, org permission `view_contacts`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "q", "in": "query", "required": false, "description": "Substring filter on the address or domain.", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "required": false, "description": "Page size, 1 to 200. Default 50.", "schema": { "type": "integer" } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque pagination cursor from the previous page's pagination.next_cursor.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "A page of suppression entries.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SuppressionListResult" } } } }, "400": { "description": "Invalid limit or cursor.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks READ_CONTACTS or the member lacks view_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "tags": [ "deliverability-ops" ], "operationId": "deliverability-ops_add_suppressions", "summary": "Add to the suppression list", "description": "Adds addresses and domains. Unparseable values are reported in `skipped`; existing entries are updated in place, so the call is safe to repeat. Scope `WRITE_CONTACTS`, org permission `manage_contacts`.", "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddSuppressionsRequest" } } } }, "responses": { "200": { "description": "What the request did.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddSuppressionsResult" } } } }, "400": { "description": "No entries, or more than 5000.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks WRITE_CONTACTS or the member lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/suppressions/{id}": { "delete": { "tags": [ "deliverability-ops" ], "operationId": "deliverability-ops_remove_suppression", "summary": "Remove from the suppression list", "description": "Lifts one entry so campaigns can email the address (or every address at the domain) again. Recorded in the audit log. Scope `WRITE_CONTACTS`, org permission `manage_contacts`.", "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "204": { "description": "Entry removed." }, "400": { "description": "Invalid suppression ID.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API key lacks WRITE_CONTACTS or the member lacks manage_contacts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such entry in this organization.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/folders": { "post": { "operationId": "labels_create_folder", "summary": "Create folder", "description": "Campaign folders. The new entry lands at the end of the workspace's registry. A registry holds at most 100 entries.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateLabel" } } } }, "responses": { "200": { "description": "The created folder.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Label" } } } }, "400": { "description": "Invalid title or colour, or the registry is full.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/folders/{id}": { "patch": { "operationId": "labels_update_folder", "summary": "Update folder", "description": "Rename or recolour a folder. Any member of the workspace may, whoever created it.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Folder ID." } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateLabel" } } } }, "responses": { "200": { "description": "The updated folder.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Label" } } } }, "400": { "description": "Invalid title or colour.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such folder in this workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "labels_delete_folder", "summary": "Delete folder", "description": "Removes the folder and unfiles everything it was attached to. The records themselves are kept.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Folder ID." } ], "responses": { "204": { "description": "Deleted." }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such folder in this workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/folders/{id}/move": { "patch": { "operationId": "labels_move_folder", "summary": "Move folder", "description": "Reorders the registry by placing this folder at `position`. Returns the full new ordering.", "tags": [ "campaigns" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Folder ID." } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MoveLabel" } } } }, "responses": { "200": { "description": "Every folder with its new position.", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/LabelOrder" } } } } }, "400": { "description": "Position out of range.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such folder in this workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tags": { "post": { "operationId": "labels_create_tag", "summary": "Create tag", "description": "Mailbox tags. The new entry lands at the end of the workspace's registry. A registry holds at most 100 entries.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateLabel" } } } }, "responses": { "200": { "description": "The created tag.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Label" } } } }, "400": { "description": "Invalid title or colour, or the registry is full.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tags/{id}": { "patch": { "operationId": "labels_update_tag", "summary": "Update tag", "description": "Rename or recolour a tag. Any member of the workspace may, whoever created it.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Tag ID." } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateLabel" } } } }, "responses": { "200": { "description": "The updated tag.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Label" } } } }, "400": { "description": "Invalid title or colour.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such tag in this workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "labels_delete_tag", "summary": "Delete tag", "description": "Removes the tag and unfiles everything it was attached to. The records themselves are kept.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Tag ID." } ], "responses": { "204": { "description": "Deleted." }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such tag in this workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tags/{id}/move": { "patch": { "operationId": "labels_move_tag", "summary": "Move tag", "description": "Reorders the registry by placing this tag at `position`. Returns the full new ordering.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Tag ID." } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MoveLabel" } } } }, "responses": { "200": { "description": "Every tag with its new position.", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/LabelOrder" } } } } }, "400": { "description": "Position out of range.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such tag in this workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/categories": { "post": { "operationId": "labels_create_category", "summary": "Create category", "description": "Contact categories, which double as unified-inbox conversation labels. The new entry lands at the end of the workspace's registry. A registry holds at most 100 entries.", "tags": [ "contacts" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateLabel" } } } }, "responses": { "200": { "description": "The created category.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Label" } } } }, "400": { "description": "Invalid title or colour, or the registry is full.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/categories/{id}": { "patch": { "operationId": "labels_update_category", "summary": "Update category", "description": "Rename or recolour a category. Any member of the workspace may, whoever created it.", "tags": [ "contacts" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Category ID." } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateLabel" } } } }, "responses": { "200": { "description": "The updated category.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Label" } } } }, "400": { "description": "Invalid title or colour.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such category in this workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "labels_delete_category", "summary": "Delete category", "description": "Removes the category and unfiles everything it was attached to. The records themselves are kept.", "tags": [ "contacts" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Category ID." } ], "responses": { "204": { "description": "Deleted." }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such category in this workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/categories/{id}/move": { "patch": { "operationId": "labels_move_category", "summary": "Move category", "description": "Reorders the registry by placing this category at `position`. Returns the full new ordering.", "tags": [ "contacts" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Category ID." } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MoveLabel" } } } }, "responses": { "200": { "description": "Every category with its new position.", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/LabelOrder" } } } } }, "400": { "description": "Position out of range.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid credentials.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing required scope or permission.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such category in this workspace.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/imports/preview": { "post": { "operationId": "mailbox_imports_preview", "summary": "Preview a mailbox import", "description": "What an import of this input would do, row by row and domain by domain, without doing any of it. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/MailboxImportForm" } } } }, "responses": { "200": { "description": "The preview.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxImportPreview" } } } }, "400": { "description": "Invalid input, file over 10 MB (mailbox_import_too_large), or more rows than one import takes.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/imports": { "get": { "operationId": "mailbox_imports_list", "summary": "List mailbox imports", "description": "The workspace's imports, newest first. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "limit", "in": "query", "schema": { "type": "integer", "maximum": 100 } }, { "name": "cursor", "in": "query", "schema": { "type": "string" } } ], "responses": { "200": { "description": "A page of imports.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data", "pagination" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/MailboxImport" } }, "pagination": { "type": "object", "required": [ "has_more" ], "properties": { "next_cursor": { "type": "string", "description": "Opaque cursor for the next page; empty on the last page." }, "has_more": { "type": "boolean" } } } } } } } }, "400": { "description": "Invalid limit or cursor (invalid_cursor).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "mailbox_imports_create", "summary": "Create a mailbox import", "description": "Stores the rows and connects them in the background. Repeating it makes a second import, whose rows find the first one's mailboxes already connected. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/MailboxImportForm" } } } }, "responses": { "201": { "description": "The import.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxImport" } } } }, "400": { "description": "Invalid input or file over 10 MB.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/imports/{id}": { "get": { "operationId": "mailbox_imports_get", "summary": "Get a mailbox import", "description": "One import with its counts and its failures grouped by cause. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Import id." } ], "responses": { "200": { "description": "The import.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxImport" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Import not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/imports/{id}/rows": { "get": { "operationId": "mailbox_imports_rows", "summary": "List an import's rows", "description": "An import's rows by line, filtered by status (comma-separated) and cause. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Import id." }, { "name": "status", "in": "query", "schema": { "type": "string" } }, { "name": "cause", "in": "query", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "schema": { "type": "integer", "maximum": 200 } }, { "name": "cursor", "in": "query", "schema": { "type": "string" } } ], "responses": { "200": { "description": "A page of rows.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data", "pagination" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/MailboxImportRow" } }, "pagination": { "type": "object", "required": [ "has_more" ], "properties": { "next_cursor": { "type": "string", "description": "Opaque cursor for the next page; empty on the last page." }, "has_more": { "type": "boolean" } } } } } } } }, "400": { "description": "Invalid id, limit or cursor.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Import not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/imports/{id}/rows/{line}": { "patch": { "operationId": "mailbox_imports_fix_row", "summary": "Fix a failed import row", "description": "Corrects one failed row and queues it again. Refused for a row that is not failed. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Import id." }, { "name": "line", "in": "path", "required": true, "schema": { "type": "integer" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxImportRowFix" } } } }, "responses": { "200": { "description": "The row.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxImportRow" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Import or row not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/imports/{id}/retry": { "post": { "operationId": "mailbox_imports_retry", "summary": "Retry failed import rows", "description": "Requeues failed rows. Only failed rows are requeued, so repeating it connects nothing twice. Possible for 7 days after the import finishes. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Import id." } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxImportRetry" } } } }, "responses": { "200": { "description": "The import.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxImport" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Import not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/imports/{id}/cancel": { "post": { "operationId": "mailbox_imports_cancel", "summary": "Cancel a mailbox import", "description": "Stops the rows not yet started; rows already connecting finish. Cancelling twice is a no-op. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Import id." } ], "responses": { "200": { "description": "The import.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxImport" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Import not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/imports/{id}/failed.csv": { "get": { "operationId": "mailbox_imports_failed_csv", "summary": "Download failed import rows", "description": "Every row that did not connect, as uploaded minus passwords, with status, problem and how_to_fix. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Import id." } ], "responses": { "200": { "description": "The CSV.", "content": { "text/csv": { "schema": { "type": "string" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Import not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/vendors/catalog": { "get": { "operationId": "mailbox_vendors_catalog", "summary": "List supported inbox vendors", "description": "The supported vendors, with the fields each one asks for. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The catalog.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/MailboxVendor" } } } } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/vendors": { "get": { "operationId": "mailbox_vendors_list", "summary": "List inbox vendor connections", "description": "The workspace's vendor connections with status, last error and mailbox count. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The connections.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/VendorConnection" } } } } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "operationId": "mailbox_vendors_create", "summary": "Connect an inbox vendor", "description": "Checks the key with the vendor, then stores it sealed with the workspace's key. Repeating it makes a second connection. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VendorConnectionInput" } } } }, "responses": { "201": { "description": "The connection.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VendorConnection" } } } }, "400": { "description": "Invalid body, unknown vendor, missing field, or the vendor refused the key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/vendors/{id}": { "patch": { "operationId": "mailbox_vendors_update", "summary": "Update an inbox vendor connection", "description": "Renames it, or replaces its fields after checking the new key with the vendor. Safe to repeat. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VendorConnectionInput" } } } }, "responses": { "200": { "description": "The connection.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VendorConnection" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Connection not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "mailbox_vendors_delete", "summary": "Delete an inbox vendor connection", "description": "Forgets the key; the mailboxes it brought in stay connected. A repeat is a 404. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." } ], "responses": { "204": { "description": "Deleted." }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Connection not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/vendors/{id}/mailboxes": { "get": { "operationId": "mailbox_vendors_mailboxes", "summary": "List a vendor account's mailboxes", "description": "Each mailbox is marked connected when already in the workspace. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." } ], "responses": { "200": { "description": "The mailboxes.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/VendorMailbox" } } } } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Connection not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/vendors/{id}/import": { "post": { "operationId": "mailbox_vendors_import", "summary": "Import a vendor account's mailboxes", "description": "mailbox_ids or all, plus import options. Each call creates a new import; a repeat finds the first run's mailboxes connected and updates (or skips) them. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Connection id." } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxSourceImportRequest" } } } }, "responses": { "201": { "description": "The import.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxImport" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Connection not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/onboarding/app-password/{id}": { "post": { "operationId": "mailbox_switch_app_password", "summary": "Switch a mailbox to an app password", "description": "Moves a mailbox connected with per-mailbox Google sign-in onto Gmail's IMAP and SMTP with a Google app password. The password is checked against imap.gmail.com and smtp.gmail.com before anything is stored; a refusal answers with the same codes as an SMTP/IMAP connect, such as mailbox_auth_refused, and changes nothing. On success the mailbox becomes smtp_imap with auth_method app_password in place, keeping its id, imported mail, campaigns, warmup and settings. A repeat answers 409 mailbox_not_google_signin, so it changes nothing. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Mailbox id." } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "app_password" ], "properties": { "app_password": { "type": "string", "description": "A 16-letter Google app password. Spaces are ignored.", "example": "abcd efgh ijkl mnop" } } } } } }, "responses": { "200": { "description": "The mailbox.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Mailbox" } } } }, "400": { "description": "Invalid request, app_password is not 16 letters (app_password_invalid), or Gmail refused the password (mailbox_auth_refused and the other SMTP/IMAP connect codes).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Mailbox not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "The mailbox is not connected with per-mailbox Google sign-in (mailbox_not_google_signin).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "No worker could check the password.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/grants/config": { "get": { "operationId": "mailbox_grants_config", "summary": "Get admin grant settings", "description": "Whether this instance takes Google and Microsoft grants, what a Google administrator authorizes, and the settings still unset. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The settings.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DomainGrantConfig" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/grants": { "get": { "operationId": "mailbox_grants_list", "summary": "List admin grants", "description": "The workspace's Google Workspace and Microsoft 365 grants. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The grants.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/DomainGrant" } } } } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/grants/migration": { "get": { "operationId": "mailbox_grants_signin_migration", "summary": "List mailboxes on per-mailbox Google sign-in", "description": "The workspace's mailboxes still connected with per-mailbox Google sign-in, which is being retired, grouped by domain with where each moves: an admin grant (workspace) or an app password (personal). Mailboxes whose sign-in Warmbly Cloud holds are not listed. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The mailboxes by domain.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data", "total" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/SigninMigration" } }, "total": { "type": "integer", "description": "How many mailboxes are listed across every domain." } } } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/grants/google/start": { "post": { "operationId": "mailbox_grants_google_start", "summary": "Start a Google Workspace grant", "description": "Takes domain and admin_email (on that domain) and answers how this workspace proves it controls the domain: a Google sign-in as that administrator, or a TXT record at _warmbly.. Safe to repeat. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "domain", "admin_email" ], "properties": { "domain": { "type": "string" }, "admin_email": { "type": "string" } } } } } }, "responses": { "200": { "description": "The proof to complete.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GoogleGrantStart" } } } }, "400": { "description": "Invalid body, admin_email not on domain (mailbox_grant_domain_mismatch), or Google grants not set up (mailbox_grant_not_configured).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/grants/google/finish": { "post": { "operationId": "mailbox_grants_google_finish", "summary": "Finish a Google Workspace grant", "description": "Records the grant once the domain is proved (the sign-in was admin_email on that domain, or the TXT record holds this workspace's value) and the directory lists admin_email as a super administrator. A state is single-use; repeating a DNS finish re-verifies and updates the same grant. Requires a user session token (not an API key) and the manage_emails organization permission. Also requires a recent confirmation (POST /auth/reauth); without one it answers 403 with code reauth_required.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GoogleGrantFinish" } } } }, "responses": { "201": { "description": "The grant.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DomainGrant" } } } }, "400": { "description": "Invalid body, or a refusal with a stable code such as mailbox_grant_not_configured, mailbox_grant_state_invalid, mailbox_grant_proof_missing or google_delegation_unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, called with an API key, or no recent confirmation (reauth_required).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Google or the DNS lookup did not answer (mailbox_grant_unavailable).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/grants/microsoft/start": { "post": { "operationId": "mailbox_grants_microsoft_start", "summary": "Start a Microsoft 365 grant", "description": "The admin consent URL a Global Administrator opens, and its state, valid for 15 minutes. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The consent URL.", "content": { "application/json": { "schema": { "type": "object", "properties": { "url": { "type": "string" }, "state": { "type": "string" } } } } } }, "400": { "description": "Microsoft grants not set up (mailbox_grant_not_configured).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/grants/microsoft/finish": { "post": { "operationId": "mailbox_grants_microsoft_finish", "summary": "Finish a Microsoft 365 grant", "description": "Takes state and code from the consent callback. The organization recorded is the one the administrator consented for, read from the redeemed sign-in. The state is single-use; consenting again for the same organization updates the same grant. Requires a user session token (not an API key) and the manage_emails organization permission. Also requires a recent confirmation (POST /auth/reauth); without one it answers 403 with code reauth_required.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "state", "code" ], "properties": { "state": { "type": "string" }, "code": { "type": "string" } } } } } }, "responses": { "201": { "description": "The grant.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DomainGrant" } } } }, "400": { "description": "Invalid body, or a refusal such as mailbox_grant_state_invalid or microsoft_consent_missing.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, called with an API key, or no recent confirmation (reauth_required).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Microsoft did not answer (mailbox_grant_unavailable).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/grants/{id}": { "get": { "operationId": "mailbox_grants_get", "summary": "Get an admin grant", "description": "One grant with its covered domains, status and mailbox count. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Grant id." } ], "responses": { "200": { "description": "The grant.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DomainGrant" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Grant not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "operationId": "mailbox_grants_delete", "summary": "Delete an admin grant", "description": "Removes the grant; every mailbox it connected stops. A repeat is a 404. Requires a user session token (not an API key) and the manage_emails organization permission. Also requires a recent confirmation (POST /auth/reauth); without one it answers 403 with code reauth_required.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Grant id." } ], "responses": { "204": { "description": "Deleted." }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, called with an API key, or no recent confirmation (reauth_required).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Grant not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/grants/{id}/check": { "post": { "operationId": "mailbox_grants_check", "summary": "Check an admin grant", "description": "Verifies the grant now, and restarts its stopped mailboxes when it passes. Safe to repeat. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Grant id." } ], "responses": { "200": { "description": "The grant.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DomainGrant" } } } }, "400": { "description": "Invalid body, or a refusal with a stable code such as mailbox_grant_not_configured, mailbox_grant_state_invalid, mailbox_grant_proof_missing or google_delegation_unauthorized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Grant not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "The provider did not answer (mailbox_grant_unavailable); the grant is left as it was.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/grants/{id}/users": { "get": { "operationId": "mailbox_grants_users", "summary": "List a grant's directory", "description": "The granted directory, each user marked enabled and connected; upgrade marks a mailbox here on its own sign-in that connecting moves onto the grant. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Grant id." } ], "responses": { "200": { "description": "The users.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/DirectoryUser" } } } } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Grant not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "The provider did not answer (mailbox_grant_unavailable).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/grants/{id}/connect": { "post": { "operationId": "mailbox_grants_connect", "summary": "Connect users through an admin grant", "description": "user_ids or all (every enabled user not yet connected, plus every user marked upgrade), plus import options; runs as a background import. A user whose delegated mailbox is already in the workspace is relinked to this grant, and one on its own sign-in is moved onto the grant in place. Requires a user session token (not an API key) and the manage_emails organization permission. Also requires a recent confirmation (POST /auth/reauth); without one it answers 403 with code reauth_required.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Grant id." } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxSourceImportRequest" } } } }, "responses": { "201": { "description": "The import.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MailboxImport" } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, called with an API key, or no recent confirmation (reauth_required).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Grant not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/domains": { "get": { "operationId": "sending_domains_list", "summary": "List sending domains", "description": "Every domain the workspace sends from, with authentication, tracking hosts, the redirect, and vendor_domain when a connected inbox vendor account holds the domain. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "The domains.", "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/SendingDomain" } } } } } } }, "400": { "description": "Invalid request.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid session token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Missing manage_emails permission, or called with an API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Rate limited.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/emails/domains/bulk": { "post": { "operationId": "sending_domains_bulk_setup", "summary": "Set up many sending domains at once", "description": "Sets link-style tracking hosts (.) and a root redirect to one website on up to 100 domains. Each domain takes the easiest path: its inbox vendor writes the CNAME or forwards the root when its API can, otherwise the host or redirect is saved and waits for DNS. Every row reports its own outcome. Safe to retry: each setting is set, not added. Requires a user session token (not an API key) and the manage_emails organization permission.", "tags": [ "mailboxes" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "domains" ], "properties": { "domains": { "type": "array", "items": { "type": "string" }, "minItems": 1, "maxItems": 100 }, "tracking_label": { "type": "string", "description": "One DNS label, such as link. Each domain gets