{
  "openapi": "3.1.0",
  "info": {
    "title": "CallLoop OpenApi definition",
    "description": "REST API for managing contacts and sending SMS, voice, and ringless messages from your own systems.\n\n**Personal Access Token.** An organization owner creates a token in CallLoop (API settings, or GraphQL `createPersonalAccessToken`). The secret is shown once. Grant `contact:read` / `contact:write` and `message:read` / `message:write` as needed.\n\n**Header.** Send every request with `Authorization: Bearer pat_v1.<token>`. The `pat_v1.` prefix is required.\n\n**Phone numbers.** Prefer E.164 (`+15551234567`). National US numbers without a country code are accepted. `fromNumber` on send must belong to your account. Invalid `fromNumber` or `toNumber` returns HTTP 400 naming the field.\n\n**Send, then poll.** `POST /api/public/v1/message/sms|voice|ringless` accepts the message and returns HTTP 200 with `state.status` = `Queued`. That means it is accepted for sending, not that the carrier delivered it. Poll `GET /api/public/v1/message/{id}` with the returned numeric `id` or `state.uuid` until a terminal status (`Delivered`, `Sent`, `Failed`, `Skipped`, and similar).\n\n**Rate limits.** The gateway may return HTTP 429 when the organization exceeds its request quota. SMS from a given number may also be throttled (about 2 messages per second when throttling is enabled). Retry with backoff.\n\n**Media IDs.** `assetIds`, `cardIds`, `audioIds`, and `audioId` must already exist in the account. Upload audio and assets in CallLoop first; send endpoints do not accept file uploads.\n\n**Sorting.** List endpoints accept `sort` as `property,asc` or `property,desc`. Example: `sort=createdAt,desc`. Repeat `sort` to order by more than one field. An unknown property or direction returns HTTP 400 naming the invalid value.\n",
    "version": "v1"
  },
  "servers": [
    {
      "url": "https://api.callloop.com"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Contacts",
      "description": "Create, look up, and update contacts. Requires a PAT with contact:read or contact:write."
    },
    {
      "name": "Assets",
      "description": "Upload and manage assets"
    },
    {
      "name": "Contact cards",
      "description": "Create and manage contact cards"
    },
    {
      "name": "Lists",
      "description": "Create and manage contact lists"
    },
    {
      "name": "Messages",
      "description": "Send SMS, voice, and ringless voicemail, then poll for delivery. Requires a PAT with message:read or message:write."
    },
    {
      "name": "Audio",
      "description": "Upload and manage audio"
    }
  ],
  "paths": {
    "/api/public/v1/lists/{listId}": {
      "put": {
        "tags": [
          "Lists"
        ],
        "summary": "Update a list",
        "description": "Updates the list name. The list id is taken from the path and is not read from the body.",
        "operationId": "update",
        "parameters": [
          {
            "name": "listId",
            "in": "path",
            "description": "List ID",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "selectedFields",
            "in": "query",
            "description": "Statistics fields to include, e.g. totalContactsCount, activeContactsCount",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "uniqueItems": true
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/{contactId}": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "Get a contact",
        "description": "Use this to load one contact by numeric ID after create, or when you already store the ID.\n\nRequired: path `contactId`. Optional: none.\n",
        "operationId": "getById",
        "parameters": [
          {
            "name": "contactId",
            "in": "path",
            "description": "Contact ID",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Contact as stored (`status`, opt-in, lists, custom fields). Not a message delivery confirmation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactLightResponse"
                },
                "example": {
                  "id": 1,
                  "firstName": "Jane",
                  "lastName": "Doe",
                  "phone": "+15555550100",
                  "status": "Active",
                  "subscriptionState": "SUBSCRIBED"
                }
              }
            }
          },
          "404": {
            "description": "No contact with that id exists in your organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactLightResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "put": {
        "tags": [
          "Contacts"
        ],
        "summary": "Update a contact",
        "description": "Use this to replace fields on an existing contact (full update).\n\nRequired: path `contactId` and a body. `phoneNumber` is required to change or keep the number. Other fields are optional; omitted values may be cleared depending on the field.\n",
        "operationId": "update_1",
        "parameters": [
          {
            "name": "contactId",
            "in": "path",
            "description": "Contact ID",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactApiRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Contact after save. Not a send or delivery result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactLightResponse"
                },
                "example": {
                  "id": 1,
                  "firstName": "Jane",
                  "lastName": "Doe",
                  "phone": "+15555550100",
                  "status": "Active",
                  "subscriptionState": "SUBSCRIBED"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "tags": [
          "Contacts"
        ],
        "summary": "Partially update a contact",
        "description": "Use this to change only the fields you send (partial update). Unspecified fields are left as they are.\n\nRequired: path `contactId`. Optional body: any subset of contact fields, including an empty body.\n",
        "operationId": "patch",
        "parameters": [
          {
            "name": "contactId",
            "in": "path",
            "description": "Contact ID",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactApiRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contact after the patch. Not a send or delivery result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactLightResponse"
                },
                "example": {
                  "id": 1,
                  "firstName": "Jane",
                  "lastName": "Doe",
                  "phone": "+15555550100",
                  "status": "Active",
                  "subscriptionState": "SUBSCRIBED"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/opt-in-status": {
      "put": {
        "tags": [
          "Contacts"
        ],
        "summary": "Update contact opt-in status",
        "description": "Use this to set SMS and call/ringless subscription states for one contact.\n\nRequired: `contactId` plus `textMessageState` and/or `callAndRinglessState` (`SUBSCRIBED` or `SOFT_UNSUBSCRIBED`). Optional: omit a channel to leave it unchanged if the body allows.\n",
        "operationId": "updateContactOptInStatus",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactOptInStatusData"
              },
              "example": {
                "contactId": 1,
                "textMessageState": "SUBSCRIBED",
                "callAndRinglessState": "SOFT_UNSUBSCRIBED"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Saved opt-in payload. No message is sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactOptInStatusData"
                },
                "example": {
                  "contactId": 1,
                  "textMessageState": "SUBSCRIBED",
                  "callAndRinglessState": "SOFT_UNSUBSCRIBED"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contact-cards/{contactCardId}": {
      "put": {
        "tags": [
          "Contact cards"
        ],
        "summary": "Update a contact card",
        "operationId": "update_2",
        "parameters": [
          {
            "name": "contactCardId",
            "in": "path",
            "description": "Contact card ID",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactCardRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ContactCardResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/audio": {
      "get": {
        "tags": [
          "Audio"
        ],
        "summary": "List audio files",
        "description": "Returns a paginated list of audio files, optionally filtered by name",
        "operationId": "getAll",
        "parameters": [
          {
            "name": "pattern",
            "in": "query",
            "description": "Optional audio name filter",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Zero-based page index (0..N)",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "description": "The size of the page to be returned",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Sort as property,asc or property,desc. Example: createdAt,desc. An unknown property or direction returns HTTP 400.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "example": "createdAt,desc"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/PageResponseAudioItem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "put": {
        "tags": [
          "Audio"
        ],
        "summary": "Update an audio file",
        "operationId": "update_3",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAudioItemRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/AudioItem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "tags": [
          "Audio"
        ],
        "summary": "Delete audio files",
        "operationId": "delete",
        "parameters": [
          {
            "name": "ids",
            "in": "query",
            "description": "IDs of audio files to delete",
            "required": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/message/voice": {
      "post": {
        "tags": [
          "Messages"
        ],
        "summary": "Send a voice message",
        "description": "Use this to queue one outbound voice call (uploaded audio for live answer and/or voicemail).\n\nRequired: `fromNumber`, `toNumber`, and `voiceMessage` with at least one enabled audio (`liveAnswer.audioId` and/or `voiceMail.audioId`). Optional: `validOnly` (skip DNC contacts), `premiumAmDetectionEnabled`, transfer settings. Audio IDs must already exist in the account.\n",
        "operationId": "sendVoice",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApiSendVoiceRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Call queued (`state.status` = `Queued`), not answered or delivered. DNC + `validOnly` may already be `Skipped`.",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/MessageDataResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid payload, missing audio, or `fromNumber` / `toNumber` failed format validation."
          },
          "404": {
            "description": "Call transfer is enabled but `liveAnswer.transferCallNumber` was not provided."
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/message/sms": {
      "post": {
        "tags": [
          "Messages"
        ],
        "summary": "Send an SMS message",
        "description": "Use this to queue one SMS. The destination contact is matched or created from `toNumber`.\n\nRequired: `fromNumber` (a number on your account), `toNumber`, and `smsMessage` (`text` is the body). Optional: `validOnly`, `compliance` / `complianceText`, `shortenUrls`, `assetIds`, `cardIds`, `audioIds`. `shortenUrls` replaces URLs in `text` with tracked short links before the message is queued. Those media IDs must already exist in CallLoop; this endpoint does not upload files. `validOnly` is accepted on SMS but DNC skip at queue time applies to voice and ringless.\n",
        "operationId": "sendSms",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApiSendSmsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Message queued (`state.status` = `Queued`), not delivered. Poll GET /api/public/v1/message/{id}.",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/MessageDataResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid payload, empty SMS `text`, or `fromNumber` / `toNumber` failed format validation."
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/message/ringless": {
      "post": {
        "tags": [
          "Messages"
        ],
        "summary": "Send a ringless voicemail",
        "description": "Use this to queue a ringless voicemail drop.\n\nRequired: `fromNumber`, `toNumber`, and `ringlessMessage.audioId` (an audio item already uploaded in CallLoop). Optional: `validOnly` (skip DNC contacts), `callbackEnabled`.\n",
        "operationId": "sendRingless",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApiSendRinglessRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Drop queued (`state.status` = `Queued`), not deposited. DNC + `validOnly` may already be `Skipped`.",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/MessageDataResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid payload, missing `audioId`, or `fromNumber` / `toNumber` failed format validation."
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/lists": {
      "get": {
        "tags": [
          "Lists"
        ],
        "summary": "Get organization lists",
        "operationId": "getAll_1",
        "parameters": [
          {
            "name": "listingSearch",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ListingSearch"
            }
          },
          {
            "name": "selectedFields",
            "in": "query",
            "description": "Statistics fields to include",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "uniqueItems": true
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Zero-based page index (0..N)",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "description": "The size of the page to be returned",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Sort as property,asc or property,desc. Example: createdAt,desc. An unknown property or direction returns HTTP 400.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "example": "createdAt,desc"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/PageResponseListResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "tags": [
          "Lists"
        ],
        "summary": "Create a list",
        "operationId": "create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "tags": [
          "Lists"
        ],
        "summary": "Delete lists",
        "operationId": "delete_1",
        "parameters": [
          {
            "name": "listIds",
            "in": "query",
            "description": "IDs of lists to delete",
            "required": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/lists/verify-dnc": {
      "post": {
        "tags": [
          "Lists"
        ],
        "summary": "Verify DNC contact lists",
        "operationId": "verifyDncContactLists",
        "parameters": [
          {
            "name": "listIds",
            "in": "query",
            "description": "List IDs",
            "required": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ListResponse"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "List organization contacts",
        "description": "Use this to page through contacts in the authenticated organization, optionally filtered.\n\nRequired: a PAT with `contact:read`. Optional query filters: `status`, `searchPattern`, subscription states, excluded lists/contacts. Pagination: `page`, `size` (default 20, max 250), `sort` (example: `createdAt,desc`). An unknown sort property returns HTTP 400.\n",
        "operationId": "getAll_2",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Contact lifecycle filter (`Active`, `Archived`, …). Not a message delivery status.",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/ContactStatus"
            }
          },
          {
            "name": "searchPattern",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "subscriptionStates",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "SUBSCRIBED",
                  "HARD_UNSUBSCRIBED",
                  "SOFT_UNSUBSCRIBED",
                  "RE_SUBSCRIBED"
                ]
              }
            }
          },
          {
            "name": "callSubscriptionStates",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "SUBSCRIBED",
                  "HARD_UNSUBSCRIBED",
                  "SOFT_UNSUBSCRIBED",
                  "RE_SUBSCRIBED"
                ]
              }
            }
          },
          {
            "name": "excludedListIds",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          },
          {
            "name": "excludedContactIds",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Zero-based page index (0..N)",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "description": "Number of contacts per page. Default: 20. Max: 250.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Sort as property,asc or property,desc. Example: createdAt,desc. An unknown property or direction returns HTTP 400.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "example": "createdAt,desc"
          }
        ],
        "responses": {
          "200": {
            "description": "Page of contacts as stored. `status` is the contact lifecycle (`Active`, `Archived`, …), not a message delivery result. Deleted contacts are not listed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PageResponseContactLightResponse"
                },
                "example": {
                  "content": [
                    {
                      "id": 1,
                      "firstName": "Jane",
                      "lastName": "Doe",
                      "phone": "+15555550100",
                      "status": "Active",
                      "subscriptionState": "SUBSCRIBED"
                    }
                  ],
                  "pageNumber": 0,
                  "pageSize": 20,
                  "total": 1
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Create a contact",
        "description": "Use this to add a contact before sending, or to store CRM fields you will personalize later.\n\nRequired: `phoneNumber`. Optional: name, email, `timeZoneType`, `customFields`, `listIds`. Duplicate phone numbers for the same organization are rejected (unless the existing row was deleted).\n",
        "operationId": "create_1",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactApiRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Contact saved. Does not mean a message was sent or delivered.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactLightResponse"
                },
                "example": {
                  "id": 1,
                  "firstName": "Jane",
                  "lastName": "Doe",
                  "phone": "+15555550100",
                  "status": "Active",
                  "subscriptionState": "SUBSCRIBED"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "tags": [
          "Contacts"
        ],
        "summary": "Delete contacts",
        "description": "Use this to permanently delete a known set of contacts by ID.\n\nRequired: query `contactIds`. Optional: none.\n",
        "operationId": "delete_2",
        "parameters": [
          {
            "name": "contactIds",
            "in": "query",
            "description": "IDs of contacts to delete",
            "required": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Confirmation string with the number deleted. Deletes are finished in this response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/{contactId}/soft-unsubscribe": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Soft-unsubscribe a contact",
        "description": "Use this to stop messaging one contact without deleting them (soft unsubscribe / opt-out).\n\nRequired: path `contactId`. Optional: none.\n",
        "operationId": "softUnsubscribe",
        "parameters": [
          {
            "name": "contactId",
            "in": "path",
            "description": "Contact ID",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Contact with updated subscription state. No message is sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactLightResponse"
                },
                "example": {
                  "id": 1,
                  "firstName": "Jane",
                  "lastName": "Doe",
                  "phone": "+15555550100",
                  "status": "Unsubscribed",
                  "subscriptionState": "SOFT_UNSUBSCRIBED"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/{contactId}/re-subscribe": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Re-subscribe a contact",
        "description": "Use this after explicit consent to allow messaging a previously unsubscribed contact.\n\nRequired: path `contactId`. Optional: none.\n",
        "operationId": "reSubscribe",
        "parameters": [
          {
            "name": "contactId",
            "in": "path",
            "description": "Contact ID",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Contact with updated subscription state. No message is sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactLightResponse"
                },
                "example": {
                  "id": 1,
                  "firstName": "Jane",
                  "lastName": "Doe",
                  "phone": "+15555550100",
                  "status": "Active",
                  "subscriptionState": "RE_SUBSCRIBED"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/campaign-preview": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Preview contacts for campaign triggers",
        "description": "Use this to see which contacts would match campaign trigger configs before launching a campaign.\n\nRequired: a body of trigger configs. Optional: pagination (`page`, `size`, `sort`).\n",
        "operationId": "getCampaignPreviewContacts",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "description": "Zero-based page index (0..N)",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "description": "The size of the page to be returned",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Sort as property,asc or property,desc. Example: createdAt,desc. An unknown property or direction returns HTTP 400.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "example": "createdAt,desc"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CampaignTriggerConfig"
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Preview page of matching contacts. No contacts are changed and no messages are sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PageResponseContactLightResponse"
                },
                "example": {
                  "content": [
                    {
                      "id": 1,
                      "firstName": "Jane",
                      "lastName": "Doe",
                      "phone": "+15555550100",
                      "status": "Active",
                      "subscriptionState": "SUBSCRIBED"
                    }
                  ],
                  "pageNumber": 0,
                  "pageSize": 20,
                  "total": 1
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/bulk/verify-dnc": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Verify DNC contacts",
        "description": "Use this to queue or run Do-Not-Call verification for contacts.\n\nRequired: a body with `ids` or a filter. If `ids` is present, those contacts are marked for verification immediately.                     If `ids` is omitted, a background job runs.\n",
        "operationId": "verifyDncContacts",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactBulkOperationRequest"
              },
              "examples": {
                "byFilter": {
                  "summary": "By grouped filters",
                  "description": "Each inner array is an OR group. Do not send `filters` in the same request.",
                  "value": {
                    "filter": {
                      "listIds": [
                        1
                      ],
                      "sourceFilters": [
                        [
                          {
                            "field": "STATUS",
                            "type": "CONTACT",
                            "dataType": "SELECT",
                            "condition": "IN",
                            "value": "Active",
                            "orIndex": 0,
                            "andIndex": 0
                          },
                          {
                            "field": "company_name",
                            "type": "CUSTOM",
                            "dataType": "TEXT",
                            "condition": "CONTAINS_ANY",
                            "value": "Acme",
                            "orIndex": 0,
                            "andIndex": 1
                          }
                        ]
                      ]
                    }
                  }
                },
                "byIds": {
                  "summary": "By contact IDs",
                  "value": {
                    "ids": [
                      1,
                      2
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Verification requested or queued, not that DNC lookup has finished for every contact.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/bulk/unarchive": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Bulk unarchive contacts",
        "description": "Use this to restore archived contacts to Active.\n\nRequired: a body with `ids` or a filter. If `ids` is present, those contacts are unarchived immediately. If `ids` is omitted, a background job runs.\n",
        "operationId": "bulkUnArchive",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactBulkOperationRequest"
              },
              "examples": {
                "byFilter": {
                  "summary": "By grouped filters",
                  "description": "Each inner array is an OR group. Do not send `filters` in the same request.",
                  "value": {
                    "filter": {
                      "listIds": [
                        1
                      ],
                      "sourceFilters": [
                        [
                          {
                            "field": "STATUS",
                            "type": "CONTACT",
                            "dataType": "SELECT",
                            "condition": "IN",
                            "value": "Active",
                            "orIndex": 0,
                            "andIndex": 0
                          },
                          {
                            "field": "company_name",
                            "type": "CUSTOM",
                            "dataType": "TEXT",
                            "condition": "CONTAINS_ANY",
                            "value": "Acme",
                            "orIndex": 0,
                            "andIndex": 1
                          }
                        ]
                      ]
                    }
                  }
                },
                "byIds": {
                  "summary": "By contact IDs",
                  "value": {
                    "ids": [
                      1,
                      2
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Confirmation string. With `ids`, the change is already applied. Without `ids`, the job is queued, not finished.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/bulk/soft-unsubscribe": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Bulk soft-unsubscribe contacts",
        "description": "Use this to soft-unsubscribe many contacts at once.\n\nRequired: a body with `ids` or a filter (`searchPattern` / `filter`). If `ids` is present, those contacts are updated immediately. If `ids` is omitted, a background job runs.\n",
        "operationId": "bulkSoftUnsubscribe",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactBulkOperationRequest"
              },
              "examples": {
                "byFilter": {
                  "summary": "By grouped filters",
                  "description": "Each inner array is an OR group. Do not send `filters` in the same request.",
                  "value": {
                    "filter": {
                      "listIds": [
                        1
                      ],
                      "sourceFilters": [
                        [
                          {
                            "field": "STATUS",
                            "type": "CONTACT",
                            "dataType": "SELECT",
                            "condition": "IN",
                            "value": "Active",
                            "orIndex": 0,
                            "andIndex": 0
                          },
                          {
                            "field": "company_name",
                            "type": "CUSTOM",
                            "dataType": "TEXT",
                            "condition": "CONTAINS_ANY",
                            "value": "Acme",
                            "orIndex": 0,
                            "andIndex": 1
                          }
                        ]
                      ]
                    }
                  }
                },
                "byIds": {
                  "summary": "By contact IDs",
                  "value": {
                    "ids": [
                      1,
                      2
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Confirmation string. With `ids`, the change is already applied. Without `ids`, the job is queued, not finished.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/bulk/remove-from-lists": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Remove contacts from lists",
        "description": "Use this to detach contacts from one or more lists.\n\nRequired: query `listIds`, plus a body with `ids` or a filter. If `ids` is present, membership is updated immediately. If `ids` is omitted, a background job runs.\n",
        "operationId": "removeFromLists",
        "parameters": [
          {
            "name": "listIds",
            "in": "query",
            "description": "List IDs",
            "required": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactBulkOperationRequest"
              },
              "examples": {
                "byFilter": {
                  "summary": "By grouped filters",
                  "description": "Each inner array is an OR group. Do not send `filters` in the same request.",
                  "value": {
                    "filter": {
                      "listIds": [
                        1
                      ],
                      "sourceFilters": [
                        [
                          {
                            "field": "STATUS",
                            "type": "CONTACT",
                            "dataType": "SELECT",
                            "condition": "IN",
                            "value": "Active",
                            "orIndex": 0,
                            "andIndex": 0
                          },
                          {
                            "field": "company_name",
                            "type": "CUSTOM",
                            "dataType": "TEXT",
                            "condition": "CONTAINS_ANY",
                            "value": "Acme",
                            "orIndex": 0,
                            "andIndex": 1
                          }
                        ]
                      ]
                    }
                  }
                },
                "byIds": {
                  "summary": "By contact IDs",
                  "value": {
                    "ids": [
                      1,
                      2
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Confirmation string. Immediate removals are finished; a started job is queued, not complete.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/bulk/re-subscribe": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Bulk re-subscribe contacts",
        "description": "Use this to re-subscribe many contacts at once after consent.\n\nRequired: a body with `ids` or a filter. If `ids` is present, those contacts are updated immediately. If `ids` is omitted, a background job runs.\n",
        "operationId": "bulkReSubscribe",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactBulkOperationRequest"
              },
              "examples": {
                "byFilter": {
                  "summary": "By grouped filters",
                  "description": "Each inner array is an OR group. Do not send `filters` in the same request.",
                  "value": {
                    "filter": {
                      "listIds": [
                        1
                      ],
                      "sourceFilters": [
                        [
                          {
                            "field": "STATUS",
                            "type": "CONTACT",
                            "dataType": "SELECT",
                            "condition": "IN",
                            "value": "Active",
                            "orIndex": 0,
                            "andIndex": 0
                          },
                          {
                            "field": "company_name",
                            "type": "CUSTOM",
                            "dataType": "TEXT",
                            "condition": "CONTAINS_ANY",
                            "value": "Acme",
                            "orIndex": 0,
                            "andIndex": 1
                          }
                        ]
                      ]
                    }
                  }
                },
                "byIds": {
                  "summary": "By contact IDs",
                  "value": {
                    "ids": [
                      1,
                      2
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Confirmation string. With `ids`, the change is already applied. Without `ids`, the job is queued, not finished.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/bulk/delete": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Bulk delete contacts",
        "description": "Use this to permanently delete many contacts by IDs or by filter.\n\nRequired: a body with `ids` or a filter. If `ids` is present, those contacts are deleted immediately. If `ids` is omitted, a background job runs.\n",
        "operationId": "bulkDelete",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactBulkOperationRequest"
              },
              "examples": {
                "byFilter": {
                  "summary": "By grouped filters",
                  "description": "Each inner array is an OR group. Do not send `filters` in the same request.",
                  "value": {
                    "filter": {
                      "listIds": [
                        1
                      ],
                      "sourceFilters": [
                        [
                          {
                            "field": "STATUS",
                            "type": "CONTACT",
                            "dataType": "SELECT",
                            "condition": "IN",
                            "value": "Active",
                            "orIndex": 0,
                            "andIndex": 0
                          },
                          {
                            "field": "company_name",
                            "type": "CUSTOM",
                            "dataType": "TEXT",
                            "condition": "CONTAINS_ANY",
                            "value": "Acme",
                            "orIndex": 0,
                            "andIndex": 1
                          }
                        ]
                      ]
                    }
                  }
                },
                "byIds": {
                  "summary": "By contact IDs",
                  "value": {
                    "ids": [
                      1,
                      2
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Confirmation string (count deleted, or that a bulk job started). Immediate deletes are finished; a started job is queued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/bulk/archive": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Bulk archive contacts",
        "description": "Use this to archive many contacts (they leave Active lists but are not deleted).\n\nRequired: a body with `ids` or a filter. If `ids` is present, those contacts are archived immediately. If `ids` is omitted, a background job runs.\n",
        "operationId": "bulkArchive",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactBulkOperationRequest"
              },
              "examples": {
                "byFilter": {
                  "summary": "By grouped filters",
                  "description": "Each inner array is an OR group. Do not send `filters` in the same request.",
                  "value": {
                    "filter": {
                      "listIds": [
                        1
                      ],
                      "sourceFilters": [
                        [
                          {
                            "field": "STATUS",
                            "type": "CONTACT",
                            "dataType": "SELECT",
                            "condition": "IN",
                            "value": "Active",
                            "orIndex": 0,
                            "andIndex": 0
                          },
                          {
                            "field": "company_name",
                            "type": "CUSTOM",
                            "dataType": "TEXT",
                            "condition": "CONTAINS_ANY",
                            "value": "Acme",
                            "orIndex": 0,
                            "andIndex": 1
                          }
                        ]
                      ]
                    }
                  }
                },
                "byIds": {
                  "summary": "By contact IDs",
                  "value": {
                    "ids": [
                      1,
                      2
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Confirmation string. With `ids`, archive is already applied. Without `ids`, the job is queued, not finished.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/bulk/add-to-lists": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Add contacts to lists",
        "description": "Use this to attach contacts to one or more lists.\n\nRequired: query `listIds`, plus a body with `ids` or a filter. If `ids` is present, membership is updated immediately. If `ids` is omitted, a background job runs.\n",
        "operationId": "addToLists",
        "parameters": [
          {
            "name": "listIds",
            "in": "query",
            "description": "List IDs",
            "required": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactBulkOperationRequest"
              },
              "examples": {
                "byFilter": {
                  "summary": "By grouped filters",
                  "description": "Each inner array is an OR group. Do not send `filters` in the same request.",
                  "value": {
                    "filter": {
                      "listIds": [
                        1
                      ],
                      "sourceFilters": [
                        [
                          {
                            "field": "STATUS",
                            "type": "CONTACT",
                            "dataType": "SELECT",
                            "condition": "IN",
                            "value": "Active",
                            "orIndex": 0,
                            "andIndex": 0
                          },
                          {
                            "field": "company_name",
                            "type": "CUSTOM",
                            "dataType": "TEXT",
                            "condition": "CONTAINS_ANY",
                            "value": "Acme",
                            "orIndex": 0,
                            "andIndex": 1
                          }
                        ]
                      ]
                    }
                  }
                },
                "byIds": {
                  "summary": "By contact IDs",
                  "value": {
                    "ids": [
                      1,
                      2
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Confirmation string (count added, or that a bulk job started). Immediate adds are finished; a started job is queued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/active-count": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Get active contacts count for a broadcast",
        "description": "Use this to estimate how many Active contacts a broadcast filter would reach.\n\nRequired: `type` (content type) and `filterValue` in the body. Optional: none beyond the filter.\n",
        "operationId": "getActiveContactsCount",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ActiveContactsCountRequest"
              },
              "examples": {
                "sourceFilters": {
                  "summary": "Grouped source filters",
                  "description": "Each inner array is an OR group. Do not send `filters` in the same request.",
                  "value": {
                    "type": "SMS",
                    "filterValue": {
                      "listIds": [
                        1
                      ],
                      "sourceFilters": [
                        [
                          {
                            "field": "STATUS",
                            "type": "CONTACT",
                            "dataType": "SELECT",
                            "condition": "IN",
                            "value": "Active",
                            "orIndex": 0,
                            "andIndex": 0
                          },
                          {
                            "field": "company_name",
                            "type": "CUSTOM",
                            "dataType": "TEXT",
                            "condition": "CONTAINS_ANY",
                            "value": "Acme",
                            "orIndex": 0,
                            "andIndex": 1
                          }
                        ]
                      ]
                    }
                  }
                },
                "segmentFilters": {
                  "summary": "Segment-style filters",
                  "description": "Flat `filters` list. Do not send `sourceFilters` in the same request.",
                  "value": {
                    "type": "SMS",
                    "filterValue": {
                      "filters": [
                        {
                          "field": "STATUS",
                          "type": "CONTACT",
                          "dataType": "SELECT",
                          "condition": "IN",
                          "value": "Active",
                          "orIndex": 0,
                          "andIndex": 0
                        }
                      ]
                    }
                  }
                },
                "listIds": {
                  "summary": "List IDs only",
                  "value": {
                    "type": "SMS",
                    "filterValue": {
                      "listIds": [
                        1
                      ]
                    }
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Integer count of matching Active contacts. Not a send and does not queue messages.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contact-cards": {
      "get": {
        "tags": [
          "Contact cards"
        ],
        "summary": "List contact cards",
        "description": "Returns a paginated list of contact cards",
        "operationId": "getMyContactCards",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "description": "Zero-based page index (0..N)",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "description": "The size of the page to be returned",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Sort as property,asc or property,desc. Example: createdAt,desc. An unknown property or direction returns HTTP 400.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "example": "createdAt,desc"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/PageResponseContactCardResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "tags": [
          "Contact cards"
        ],
        "summary": "Create a contact card",
        "operationId": "create_2",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactCardRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ContactCardResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "tags": [
          "Contact cards"
        ],
        "summary": "Delete contact cards",
        "operationId": "delete_3",
        "parameters": [
          {
            "name": "cardIds",
            "in": "query",
            "description": "IDs of contact cards to delete",
            "required": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/audio/upload": {
      "post": {
        "tags": [
          "Audio"
        ],
        "summary": "Upload an audio file",
        "description": "Uploads an audio file. Supported file extensions: mp3, wav. Every file uploaded through this endpoint is stored with audio type API.",
        "operationId": "upload",
        "parameters": [
          {
            "name": "content-type",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "multipart/*"
              ]
            }
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Audio file. Supported file extensions: mp3, wav."
                  }
                },
                "required": [
                  "file"
                ]
              }
            },
            "multipart/*": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Audio file. Supported file extensions: mp3, wav."
                  }
                },
                "required": [
                  "file"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AudioItem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/audio/replace": {
      "post": {
        "tags": [
          "Audio"
        ],
        "summary": "Replace an audio file",
        "description": "Replaces the file of an existing audio item. Supported file extensions: mp3, wav. The existing audio type is left unchanged. Send the target id as the form field fileInfo.audioId.",
        "operationId": "replace",
        "parameters": [
          {
            "name": "fileInfo.audioId",
            "in": "query",
            "description": "ID of the existing audio item. Send as the form field fileInfo.audioId.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "content-type",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "multipart/*"
              ]
            }
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Replacement audio file. Supported file extensions: mp3, wav."
                  }
                },
                "required": [
                  "file"
                ]
              }
            },
            "multipart/*": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Replacement audio file. Supported file extensions: mp3, wav."
                  }
                },
                "required": [
                  "file"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AudioItem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/asset/upload": {
      "post": {
        "tags": [
          "Assets"
        ],
        "summary": "Upload an asset from a URL",
        "operationId": "uploadAssetFromUrl",
        "parameters": [
          {
            "name": "content-type",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "multipart/*"
              ]
            }
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "files": {
                    "type": "array",
                    "description": "Asset files to upload",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  }
                },
                "required": [
                  "files"
                ]
              }
            },
            "multipart/*": {
              "schema": {
                "type": "object",
                "properties": {
                  "files": {
                    "type": "array",
                    "description": "Asset files to upload",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  }
                },
                "required": [
                  "files"
                ]
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadAssetRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssetsResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/message/{id}": {
      "get": {
        "tags": [
          "Messages"
        ],
        "summary": "Get a message by numeric id or state UUID",
        "description": "Use this to poll after send until a terminal status. Pass the numeric `id` or `state.uuid` from the send response.\n\nRequired: path `id`. Optional: none. Check `state.status` (full lifecycle), `state.simpleStatus` (collapsed), and `extStatus` (provider-facing). Keep polling while status is `Queued` / `Pending`.\n",
        "operationId": "getById_1",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Message numeric ID or state UUID",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current snapshot, not a delivery guarantee. `Queued`/`Pending` means still in flight.",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/MessageDataResponse"
                }
              }
            }
          },
          "404": {
            "description": "No message with that numeric id or state UUID exists in your organization."
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/message/compliance": {
      "get": {
        "tags": [
          "Messages"
        ],
        "summary": "Get a compliance message",
        "description": "Use this to read the default STOP/HELP footer that is appended when `compliance` is true on SMS send.\n\nRequired: a PAT with `message:read`. Optional: none.\n",
        "operationId": "getComplianceMessage",
        "responses": {
          "200": {
            "description": "Default compliance text string. Not a sent message and not a delivery result.",
            "content": {
              "*/*": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/lists/{listId}/contacts/statistics": {
      "get": {
        "tags": [
          "Lists"
        ],
        "summary": "Get list contacts statistics",
        "operationId": "getContactsStatistics",
        "parameters": [
          {
            "name": "listId",
            "in": "path",
            "description": "List ID",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/ContactStatisticsResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/lists/by-ids": {
      "get": {
        "tags": [
          "Lists"
        ],
        "summary": "Get lists by IDs",
        "operationId": "getByIds",
        "parameters": [
          {
            "name": "ids",
            "in": "query",
            "description": "List IDs",
            "required": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ListResponse"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/statistics": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "Get organization contacts statistics",
        "description": "Use this for dashboard totals (active, archived, unsubscribed, and similar counts).\n\nRequired: a PAT with `contact:read`. Optional: none.\n",
        "operationId": "getStatistics",
        "responses": {
          "200": {
            "description": "Current count snapshot for the organization, not a per-contact payload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactStatisticsResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/search": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "Search lists and contacts",
        "description": "Use this for a combined typeahead of lists and contacts (for example, picker UIs).\n\nRequired: none. Optional: `searchPattern` and exclusion IDs (`excludedListIds`, `excludedContactIds`, `excludedSegmentIds`).\n",
        "operationId": "searchListsAndContacts",
        "parameters": [
          {
            "name": "searchPattern",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "excludedListIds",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          },
          {
            "name": "excludedContactIds",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          },
          {
            "name": "excludedSegmentIds",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching lists and contacts. A search snapshot, not a send or delivery result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListContactSearchResult"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/by-list/{listId}": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "Get contacts by list ID",
        "description": "Use this to page contacts that belong to one list.\n\nRequired: path `listId`. Optional: the same `ContactSearch` filters and pagination as list contacts.\n",
        "operationId": "getListContacts",
        "parameters": [
          {
            "name": "listId",
            "in": "path",
            "description": "List ID",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Contact lifecycle filter (`Active`, `Archived`, …). Not a message delivery status.",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/ContactStatus"
            }
          },
          {
            "name": "searchPattern",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "subscriptionStates",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "SUBSCRIBED",
                  "HARD_UNSUBSCRIBED",
                  "SOFT_UNSUBSCRIBED",
                  "RE_SUBSCRIBED"
                ]
              }
            }
          },
          {
            "name": "callSubscriptionStates",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "SUBSCRIBED",
                  "HARD_UNSUBSCRIBED",
                  "SOFT_UNSUBSCRIBED",
                  "RE_SUBSCRIBED"
                ]
              }
            }
          },
          {
            "name": "excludedListIds",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          },
          {
            "name": "excludedContactIds",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Zero-based page index (0..N)",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "description": "The size of the page to be returned",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Sort as property,asc or property,desc. Example: createdAt,desc. An unknown property or direction returns HTTP 400.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "example": "createdAt,desc"
          }
        ],
        "responses": {
          "200": {
            "description": "Page of contacts on that list. Membership is current as of the request; not a message status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PageResponseContactLightResponse"
                },
                "example": {
                  "content": [
                    {
                      "id": 1,
                      "firstName": "Jane",
                      "lastName": "Doe",
                      "phone": "+15555550100",
                      "status": "Active",
                      "subscriptionState": "SUBSCRIBED"
                    }
                  ],
                  "pageNumber": 0,
                  "pageSize": 20,
                  "total": 1
                }
              }
            }
          },
          "404": {
            "description": "No list with that id exists in your organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PageResponseContactLightResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/contacts/by-ids": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "Get contacts by IDs",
        "description": "Use this to load a known set of contacts in one call after you already store their IDs.\n\nRequired: query `contactIds`. Optional: none.\n",
        "operationId": "getByIds_1",
        "parameters": [
          {
            "name": "contactIds",
            "in": "query",
            "description": "Contact IDs",
            "required": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Contacts found in your organization. Missing IDs are omitted; not a delivery confirmation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ContactLightResponse"
                  }
                },
                "example": [
                  {
                    "id": 1,
                    "firstName": "Jane",
                    "lastName": "Doe",
                    "phone": "+15555550100",
                    "status": "Active",
                    "subscriptionState": "SUBSCRIBED"
                  }
                ]
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/audio/exists": {
      "get": {
        "tags": [
          "Audio"
        ],
        "summary": "Check if an audio name exists",
        "operationId": "checkExists",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "description": "Audio file name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "type": "boolean"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/public/v1/asset": {
      "get": {
        "tags": [
          "Assets"
        ],
        "summary": "List assets",
        "description": "Returns a paginated list of assets",
        "operationId": "getMyAssets",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "description": "Zero-based page index (0..N)",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "description": "The size of the page to be returned",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Sort as property,asc or property,desc. Example: createdAt,desc. An unknown property or direction returns HTTP 400.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "example": "createdAt,desc"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/PageResponseAssetResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "tags": [
          "Assets"
        ],
        "summary": "Delete assets",
        "operationId": "removeAssets",
        "parameters": [
          {
            "name": "assetIds",
            "in": "query",
            "description": "IDs of assets to delete",
            "required": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int64"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "*/*": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "ListCreateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          }
        }
      },
      "KeywordForm": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string"
          }
        }
      },
      "ListResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "webForms": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebFormForm"
            }
          },
          "keywords": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KeywordForm"
            }
          },
          "totalContactsCount": {
            "type": "integer",
            "format": "int64"
          },
          "activeContactsCount": {
            "type": "integer",
            "format": "int64"
          },
          "invalidContactsCount": {
            "type": "integer",
            "format": "int64"
          },
          "unsubscribedContactsCount": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "WebFormForm": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string"
          }
        }
      },
      "ContactApiRequest": {
        "type": "object",
        "properties": {
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "phoneNumber": {
            "type": "string",
            "description": "Contact phone number. Required on create and full update; optional on patch. Prefer E.164 (`+15551234567`); national US format is accepted."
          },
          "timeZoneType": {
            "type": "string",
            "enum": [
              "EASTERN",
              "EAST_INDIANA",
              "MICHIGAN",
              "CENTRAL",
              "MOUNTAIN",
              "ARIZONA",
              "PACIFIC",
              "ALASKA",
              "HAWAII",
              "ATLANTIC",
              "NEWFOUNDLAND",
              "SASKATCHEWAN",
              "UNDEFINED"
            ]
          },
          "customFields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContactCustomFieldRequest"
            }
          },
          "listIds": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int64"
            }
          }
        }
      },
      "ContactCustomFieldRequest": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "value": {
            "type": "string"
          }
        }
      },
      "ContactCustomFieldResponse": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string"
          },
          "number": {
            "type": "integer",
            "format": "int64"
          },
          "date": {
            "type": "string",
            "format": "date-time"
          },
          "numeric": {
            "type": "number"
          },
          "currencyType": {
            "type": "string",
            "enum": [
              "USD"
            ]
          },
          "key": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string"
          }
        }
      },
      "ContactLightResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string"
          },
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "internationalPhoneNumber": {
            "type": "string"
          },
          "optIn": {
            "type": "string",
            "enum": [
              "AddedManually",
              "Imported",
              "Integrated",
              "AddedByKeyword",
              "AddedByWebForm",
              "Migrated",
              "API"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/ContactStatus",
            "description": "Contact lifecycle (`Active`, `Archived`, `Unsubscribed`, …). Not a message delivery status.",
            "example": "Active"
          },
          "carrierType": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "deletedAt": {
            "type": "string",
            "format": "date-time"
          },
          "subscriptionState": {
            "type": "string",
            "enum": [
              "SUBSCRIBED",
              "HARD_UNSUBSCRIBED",
              "SOFT_UNSUBSCRIBED",
              "RE_SUBSCRIBED"
            ]
          },
          "callSubscriptionState": {
            "type": "string",
            "enum": [
              "SUBSCRIBED",
              "HARD_UNSUBSCRIBED",
              "SOFT_UNSUBSCRIBED",
              "RE_SUBSCRIBED"
            ]
          },
          "dnc": {
            "type": "boolean"
          },
          "timeZoneType": {
            "type": "string",
            "enum": [
              "EASTERN",
              "EAST_INDIANA",
              "MICHIGAN",
              "CENTRAL",
              "MOUNTAIN",
              "ARIZONA",
              "PACIFIC",
              "ALASKA",
              "HAWAII",
              "ATLANTIC",
              "NEWFOUNDLAND",
              "SASKATCHEWAN",
              "UNDEFINED"
            ]
          },
          "listings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ListLightResponse"
            }
          },
          "contactCustomFields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContactCustomFieldResponse"
            }
          },
          "activity": {
            "$ref": "#/components/schemas/ContactSearchActivity"
          }
        }
      },
      "ContactSearchActivity": {
        "type": "object",
        "properties": {
          "lastContacted": {
            "type": "string",
            "format": "date-time"
          },
          "lastSms": {
            "type": "string",
            "format": "date-time"
          },
          "lastVoice": {
            "type": "string",
            "format": "date-time"
          },
          "lastRingless": {
            "type": "string",
            "format": "date-time"
          },
          "lastInbound": {
            "type": "string",
            "format": "date-time"
          },
          "lastMessageStatus": {
            "type": "string"
          },
          "totalSms": {
            "type": "integer",
            "format": "int64"
          },
          "totalVoice": {
            "type": "integer",
            "format": "int64"
          },
          "totalRingless": {
            "type": "integer",
            "format": "int64"
          },
          "lastMessageStatusAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastShortUrlClick": {
            "type": "string",
            "format": "date-time"
          },
          "lastCallback": {
            "type": "string",
            "format": "date-time"
          },
          "lastCallForward": {
            "type": "string",
            "format": "date-time"
          },
          "lastCallTransfer": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ContactStatus": {
        "type": "string",
        "enum": [
          "Active",
          "Inactive",
          "Archived",
          "Invalid",
          "Unsubscribed",
          "Deleted",
          "Dnc"
        ],
        "example": "Active"
      },
      "ListLightResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "name": {
            "type": "string"
          }
        }
      },
      "ContactOptInStatusData": {
        "type": "object",
        "description": "Contact opt-in status",
        "properties": {
          "contactId": {
            "type": "integer",
            "format": "int64"
          },
          "textMessageState": {
            "type": "string",
            "enum": [
              "SUBSCRIBED",
              "SOFT_UNSUBSCRIBED"
            ],
            "example": "SUBSCRIBED"
          },
          "callAndRinglessState": {
            "type": "string",
            "enum": [
              "SUBSCRIBED",
              "SOFT_UNSUBSCRIBED"
            ],
            "example": "SUBSCRIBED"
          }
        }
      },
      "ContactCardRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "tagline": {
            "type": "string"
          },
          "phoneNumber": {
            "type": "string"
          },
          "website": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "street": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "zipCode": {
            "type": "string"
          },
          "countryCode": {
            "type": "string"
          },
          "facebookUrl": {
            "type": "string"
          },
          "twitterUrl": {
            "type": "string"
          },
          "instagramUrl": {
            "type": "string"
          },
          "linkedinUrl": {
            "type": "string"
          },
          "youtubeUrl": {
            "type": "string"
          }
        }
      },
      "AddressResponse": {
        "type": "object",
        "properties": {
          "country": {
            "$ref": "#/components/schemas/CountryResponse"
          },
          "state": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "street": {
            "type": "string"
          },
          "zipCode": {
            "type": "string"
          }
        }
      },
      "ContactCardResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "memberId": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string"
          },
          "tagline": {
            "type": "string"
          },
          "website": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "facebookUrl": {
            "type": "string"
          },
          "twitterUrl": {
            "type": "string"
          },
          "instagramUrl": {
            "type": "string"
          },
          "linkedinUrl": {
            "type": "string"
          },
          "youtubeUrl": {
            "type": "string"
          },
          "phoneNumber": {
            "type": "string"
          },
          "formattedPhoneNumber": {
            "type": "string"
          },
          "phoneCountryCode": {
            "type": "string"
          },
          "fileSize": {
            "type": "integer",
            "format": "int64"
          },
          "address": {
            "$ref": "#/components/schemas/AddressResponse"
          }
        }
      },
      "CountryResponse": {
        "type": "object",
        "properties": {
          "countryCode": {
            "type": "string"
          },
          "countryName": {
            "type": "string"
          }
        }
      },
      "UpdateAudioItemRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string"
          }
        }
      },
      "AudioItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "deletedAt": {
            "type": "string",
            "format": "date-time"
          },
          "name": {
            "type": "string"
          },
          "sourceName": {
            "type": "string"
          },
          "sourceNameIndex": {
            "type": "integer",
            "format": "int32"
          },
          "type": {
            "type": "string",
            "enum": [
              "RECORDED_BY_COMPUTER",
              "RECORDED_BY_PHONE",
              "UPLOADED",
              "TTS",
              "MIGRATED",
              "RECORDED_BY_TWILIO",
              "EXTERNAL",
              "API"
            ]
          },
          "fileKey": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "contentType": {
            "type": "string"
          },
          "duration": {
            "type": "integer",
            "format": "int32"
          },
          "usageStatistics": {
            "$ref": "#/components/schemas/AudioUsageStatistics"
          },
          "ttsMessage": {
            "$ref": "#/components/schemas/TTSMessageTemplate"
          },
          "personalized": {
            "type": "boolean"
          }
        }
      },
      "AudioUsageSource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string"
          }
        }
      },
      "AudioUsageStatistics": {
        "type": "object",
        "properties": {
          "broadcastCount": {
            "type": "integer",
            "format": "int32"
          },
          "campaignCount": {
            "type": "integer",
            "format": "int32"
          },
          "triggerCount": {
            "type": "integer",
            "format": "int32"
          },
          "broadcasts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AudioUsageSource"
            }
          },
          "triggers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TriggerUsageSource"
            }
          },
          "campaigns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AudioUsageSource"
            }
          }
        }
      },
      "TTSCloneVoice": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "deletedAt": {
            "type": "string",
            "format": "date-time"
          },
          "name": {
            "type": "string"
          },
          "lang": {
            "type": "string"
          }
        }
      },
      "TTSExternalVoice": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string"
          },
          "externalId": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "STANDARD",
              "PREMIUM"
            ]
          },
          "pollyId": {
            "type": "string"
          }
        }
      },
      "TTSMessageTemplate": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "deletedAt": {
            "type": "string",
            "format": "date-time"
          },
          "name": {
            "type": "string"
          },
          "voice": {
            "$ref": "#/components/schemas/TTSExternalVoice"
          },
          "cloneVoice": {
            "$ref": "#/components/schemas/TTSCloneVoice"
          },
          "provider": {
            "type": "string",
            "enum": [
              "DROP_COWBOY",
              "POLLY",
              "CARTESIA"
            ]
          },
          "ttsText": {
            "type": "string"
          },
          "pollyId": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "STANDARD",
              "PREMIUM"
            ]
          }
        }
      },
      "TriggerUsageSource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string"
          },
          "app": {
            "type": "string",
            "enum": [
              "ActiveCampaign",
              "Drip",
              "Keap",
              "Custom",
              "HubSpot",
              "Zapier",
              "LeadConnector",
              "ClickBank",
              "MailChimp",
              "Shopify"
            ]
          }
        }
      },
      "ApiSendVoiceRequest": {
        "type": "object",
        "properties": {
          "fromNumber": {
            "type": "string",
            "description": "Caller ID / from number on your CallLoop account. Prefer E.164 (`+15551234567`). Invalid format returns HTTP 400 (`From number is invalid`).",
            "minLength": 1
          },
          "toNumber": {
            "type": "string",
            "description": "Destination number. Prefer E.164 (`+15551234567`). Matched or created as a contact. Invalid format returns HTTP 400 (`To number is invalid`).",
            "minLength": 1
          },
          "voiceMessage": {
            "$ref": "#/components/schemas/VoiceConfigRequest",
            "description": "Voice payload. At least one enabled audio ID is required (`liveAnswer` and/or `voiceMail`)."
          }
        },
        "required": [
          "fromNumber",
          "toNumber",
          "voiceMessage"
        ]
      },
      "LiveAnswerConfigRequest": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "transferCallEnabled": {
            "type": "boolean"
          },
          "transferCallDigit": {
            "type": "integer",
            "format": "int32"
          },
          "transferCallNumber": {
            "type": "string"
          },
          "unsubscribeDigit": {
            "type": "integer",
            "format": "int32"
          },
          "audioId": {
            "type": "integer",
            "format": "int64",
            "description": "ID of an existing audio item played on live answer. Upload audio in CallLoop first; send does not accept files."
          }
        }
      },
      "VoiceConfigRequest": {
        "type": "object",
        "properties": {
          "liveAnswer": {
            "$ref": "#/components/schemas/LiveAnswerConfigRequest"
          },
          "voiceMail": {
            "$ref": "#/components/schemas/VoiceMailConfigRequest"
          },
          "validOnly": {
            "type": "boolean",
            "description": "When true, skip sending if the destination contact is on the DNC list (`state.status` = `Skipped`). Default false."
          },
          "premiumAmDetectionEnabled": {
            "type": "boolean",
            "description": "When true, use premium answering-machine detection (more accurate AMD; may incur extra cost). Default false."
          }
        }
      },
      "VoiceMailConfigRequest": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "audioId": {
            "type": "integer",
            "format": "int64",
            "description": "ID of an existing audio item left as voicemail. Upload audio in CallLoop first; send does not accept files."
          }
        }
      },
      "MessageDataResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "state": {
            "$ref": "#/components/schemas/MessageStateResponse"
          },
          "type": {
            "type": "string",
            "enum": [
              "MMS",
              "SMS",
              "INBOUND_SMS",
              "CALL",
              "RINGLESS",
              "LOOKUP",
              "INBOUND_FORWARD_CALL"
            ]
          },
          "text": {
            "type": "string"
          },
          "totalShortUrl": {
            "type": "integer",
            "format": "int64"
          },
          "uniqueClicks": {
            "type": "integer",
            "format": "int64"
          },
          "extStatus": {
            "type": "string",
            "description": "Carrier/provider-facing status, distinct from `state.status` and `state.simpleStatus`. For SMS and ringless this is typically `simpleStatus`. For voice this is the provider call result (for example CallFire)."
          },
          "extStatusLabel": {
            "type": "string",
            "description": "Human-readable label for `extStatus`."
          },
          "duration": {
            "type": "integer",
            "format": "int32"
          },
          "penaltyApplied": {
            "type": "boolean",
            "description": "True when a short-call penalty was billed (voice duration of about 6 seconds or less). False if no penalty applied."
          },
          "extStatusDescription": {
            "type": "string",
            "description": "Human-readable explanation of `extStatus` when the provider supplies one."
          },
          "abSmsMessageId": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "MessageStateResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "source": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "timeToSend": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "type": "string",
            "description": "Full internal lifecycle: `Queued` (accepted, not yet sent), `Sent`, `Delivered`, `Failed`, `Skipped`, and similar. A send HTTP 200 with `Queued` means queued, not delivered. Distinct from `simpleStatus` (collapsed bucket) and top-level `extStatus` (provider-facing).",
            "enum": [
              "Deleted",
              "Canceled",
              "Unresolved",
              "Pending",
              "Success",
              "Running",
              "Paused",
              "Draft",
              "Archived",
              "Disabled",
              "Active",
              "Inactive",
              "Unsubscribed",
              "Subscribed",
              "Confirmed",
              "InProgress",
              "Completed",
              "Created",
              "Callback",
              "CallbackAttempt",
              "Answered",
              "Missed",
              "Processing",
              "RetryProcessing",
              "Declined",
              "Invalid",
              "Sending",
              "Queued",
              "Failed",
              "Skipped",
              "Scheduled",
              "SentToCarrier",
              "Sent",
              "Finished",
              "CollectingResults",
              "Delivered",
              "SystemDelivered",
              "Received",
              "Undelivered",
              "Trial",
              "Transferred",
              "WithConversions",
              "WithClicks",
              "Dnc"
            ]
          },
          "simpleStatus": {
            "type": "string",
            "description": "Collapsed status for clients: `Pending` (in flight, including `Queued`), `Success` (`Sent`/`Delivered`), `Failed` (`Failed`/`Declined`/`Invalid`/`Undelivered`), plus a few passthrough values (`Skipped`, `Unsubscribed`, …). Distinct from `status` (full lifecycle) and `extStatus` (provider-facing).",
            "enum": [
              "Deleted",
              "Canceled",
              "Unresolved",
              "Pending",
              "Success",
              "Running",
              "Paused",
              "Draft",
              "Archived",
              "Disabled",
              "Active",
              "Inactive",
              "Unsubscribed",
              "Subscribed",
              "Confirmed",
              "InProgress",
              "Completed",
              "Created",
              "Callback",
              "CallbackAttempt",
              "Answered",
              "Missed",
              "Processing",
              "RetryProcessing",
              "Declined",
              "Invalid",
              "Sending",
              "Queued",
              "Failed",
              "Skipped",
              "Scheduled",
              "SentToCarrier",
              "Sent",
              "Finished",
              "CollectingResults",
              "Delivered",
              "SystemDelivered",
              "Received",
              "Undelivered",
              "Trial",
              "Transferred",
              "WithConversions",
              "WithClicks",
              "Dnc"
            ]
          },
          "reason": {
            "type": "string"
          },
          "failReasonType": {
            "type": "string",
            "enum": [
              "INSUFFICIENT_FUNDS",
              "RETRY_AMOUNT_EXCEEDED"
            ]
          },
          "boundType": {
            "type": "string",
            "enum": [
              "INBOUND",
              "OUTBOUND"
            ]
          },
          "chargeAmount": {
            "type": "number",
            "format": "float"
          },
          "fromNumberId": {
            "type": "integer",
            "format": "int64"
          },
          "fromNumberStr": {
            "type": "string"
          },
          "contactId": {
            "type": "integer",
            "format": "int64"
          },
          "contactName": {
            "type": "string"
          },
          "toNumber": {
            "type": "string"
          }
        }
      },
      "ApiSendSmsRequest": {
        "type": "object",
        "properties": {
          "fromNumber": {
            "type": "string",
            "description": "Caller ID / from number on your CallLoop account. Prefer E.164 (`+15551234567`). Invalid format returns HTTP 400 (`From number is invalid`).",
            "minLength": 1
          },
          "toNumber": {
            "type": "string",
            "description": "Destination number. Prefer E.164 (`+15551234567`). Matched or created as a contact. Invalid format returns HTTP 400 (`To number is invalid`).",
            "minLength": 1
          },
          "smsMessage": {
            "$ref": "#/components/schemas/SmsConfigRequest",
            "description": "SMS payload. `text` is the body; media IDs must already exist in the account."
          }
        },
        "required": [
          "fromNumber",
          "smsMessage",
          "toNumber"
        ]
      },
      "SmsConfigRequest": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "description": "SMS body. Required on send; an empty value returns HTTP 400. Personalization tokens are resolved at send time."
          },
          "compliance": {
            "type": "boolean",
            "description": "When true, append the STOP/HELP compliance footer to the body. Use GET /api/public/v1/message/compliance for the default text."
          },
          "shortenUrls": {
            "type": "boolean",
            "description": "When true, resolve personalization tokens, then replace each URL in the body with a tracked short link on the account's primary short domain (or a default CallLoop domain). Default false. The link is stamped with this message's id at send time."
          },
          "validOnly": {
            "type": "boolean",
            "description": "When true, skip sending to contacts on the DNC list. Default false."
          },
          "complianceText": {
            "type": "string",
            "description": "Extra text appended after the standard `Reply STOP to end.` prefix when `compliance` is true. Ignored when `compliance` is false."
          },
          "assetIds": {
            "type": "array",
            "description": "IDs of existing MMS/assets in the account. Upload assets in CallLoop first; send does not accept files.",
            "items": {
              "type": "integer",
              "format": "int64"
            }
          },
          "cardIds": {
            "type": "array",
            "description": "IDs of existing contact cards in the account. Not created on send.",
            "items": {
              "type": "integer",
              "format": "int64"
            }
          },
          "audioIds": {
            "type": "array",
            "description": "IDs of existing audio items in the account. Upload audio in CallLoop first; send does not accept files.",
            "items": {
              "type": "integer",
              "format": "int64"
            }
          }
        }
      },
      "ApiSendRinglessRequest": {
        "type": "object",
        "properties": {
          "fromNumber": {
            "type": "string",
            "description": "Caller ID / from number on your CallLoop account. Prefer E.164 (`+15551234567`). Invalid format returns HTTP 400 (`From number is invalid`).",
            "minLength": 1
          },
          "toNumber": {
            "type": "string",
            "description": "Destination number. Prefer E.164 (`+15551234567`). Matched or created as a contact. Invalid format returns HTTP 400 (`To number is invalid`).",
            "minLength": 1
          },
          "ringlessMessage": {
            "$ref": "#/components/schemas/RinglessConfigRequest",
            "description": "Ringless payload. `audioId` must already exist in the account."
          }
        },
        "required": [
          "fromNumber",
          "ringlessMessage",
          "toNumber"
        ]
      },
      "RinglessConfigRequest": {
        "type": "object",
        "properties": {
          "audioId": {
            "type": "integer",
            "format": "int64",
            "description": "ID of an existing audio item in the account. Upload audio in CallLoop first; send does not accept files."
          },
          "callbackEnabled": {
            "type": "boolean"
          },
          "validOnly": {
            "type": "boolean",
            "description": "When true, skip sending if the destination contact is on the DNC list (`state.status` = `Skipped`). Default false."
          }
        }
      },
      "AutomationTriggerData": {
        "type": "object",
        "properties": {
          "triggerType": {
            "type": "string",
            "enum": [
              "MAILCHIMP_CONTACT_SUBSCRIBED",
              "CLICK_BANK_TRANSACTION",
              "CL_EMAIL_CAPTURED",
              "CL_CONTACT_ADDED_TO_LIST",
              "CL_CONTACT_REMOVED_FROM_LIST",
              "CL_CONTACT_UNSUBSCRIBED",
              "CL_CONTACT_CREATED_OR_UPDATED"
            ]
          },
          "data": {
            "type": "object",
            "additionalProperties": {}
          }
        }
      },
      "CampaignTriggerAppConfig": {
        "type": "object",
        "properties": {
          "accountIntegrationType": {
            "type": "string",
            "enum": [
              "ActiveCampaign",
              "Drip",
              "Keap",
              "Custom",
              "HubSpot",
              "Zapier",
              "LeadConnector",
              "ClickBank",
              "MailChimp",
              "Shopify"
            ]
          },
          "trigger": {
            "$ref": "#/components/schemas/AutomationTriggerData"
          }
        }
      },
      "CampaignTriggerConfig": {
        "type": "object",
        "properties": {
          "appConfig": {
            "$ref": "#/components/schemas/CampaignTriggerAppConfig"
          },
          "webhookConfig": {
            "$ref": "#/components/schemas/CampaignTriggerWebhookConfig"
          }
        }
      },
      "CampaignTriggerWebhookConfig": {
        "type": "object",
        "properties": {
          "app": {
            "type": "string",
            "enum": [
              "ActiveCampaign",
              "Drip",
              "Keap",
              "Custom",
              "HubSpot",
              "Zapier",
              "LeadConnector",
              "ClickBank",
              "MailChimp",
              "Shopify"
            ]
          },
          "appPhoneField": {
            "type": "string"
          },
          "link": {
            "type": "string"
          }
        }
      },
      "PageResponseContactLightResponse": {
        "type": "object",
        "properties": {
          "content": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContactLightResponse"
            }
          },
          "pageNumber": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "total": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "ContactBulkOperationRequest": {
        "type": "object",
        "properties": {
          "ids": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int64"
            }
          },
          "searchPattern": {
            "type": "string"
          },
          "filter": {
            "$ref": "#/components/schemas/FilterValue"
          },
          "listId": {
            "type": "integer",
            "format": "int64"
          },
          "status": {
            "$ref": "#/components/schemas/ContactStatus",
            "example": "Active"
          }
        }
      },
      "Filter": {
        "type": "object",
        "description": "A single contact filter condition.",
        "properties": {
          "field": {
            "type": "string",
            "description": "Built-in field key, or custom field key when type is CUSTOM.\n\nBuilt-in fields:\n- `FIRST_NAME` — First name (CONTACT, TEXT)\n- `LAST_NAME` — Last name (CONTACT, TEXT)\n- `EMAIL` — Email (CONTACT, TEXT)\n- `PHONE_NUMBER` — Phone number (CONTACT, PHONE)\n- `PHONE_TYPE` — Phone type (LOOKUP, TEXT)\n- `CARRIER_NAME` — Carrier name (LOOKUP, TEXT)\n- `CREATED_AT` — Created at (CONTACT, DATE)\n- `UPDATED_AT` — Updated at (CONTACT, DATE)\n- `STATUS` — Contact status (CONTACT, SELECT)\n- `OPT_IN` — Opt-in method (CONTACT, SELECT)\n- `DNC` — Do not call (LOOKUP, BOOLEAN)\n- `TIME_ZONE` — Time zone (CONTACT, SELECT)\n- `LAST_SHORT_CLICK` — Last link clicked (ACTIVITY, DATE_TIME)\n- `LAST_CALLBACK` — Last callback (ACTIVITY, DATE_TIME)\n- `LAST_CALL_FORWARD` — Last call forwarded (ACTIVITY, DATE_TIME)\n- `LAST_CALL_TRANSFER` — Last call transferred (ACTIVITY, DATE_TIME)\n- `LAST_CONTACTED` — Last contacted (ACTIVITY, DATE_TIME)\n- `LAST_SMS` — Last SMS (ACTIVITY, DATE_TIME)\n- `LAST_VOICE` — Last Voice (ACTIVITY, DATE_TIME)\n- `LAST_RINGLESS` — Last Ringless (ACTIVITY, DATE_TIME)\n- `LAST_INBOUND` — Last Inbound (ACTIVITY, DATE_TIME)\n- `LAST_MESSAGE_STATUS` — Last message status (ACTIVITY, SELECT)\n- `TOTAL_SMS` — Total SMS (ACTIVITY, NUMBER)\n- `TOTAL_VOICE` — Total Voice (ACTIVITY, NUMBER)\n- `TOTAL_RINGLESS` — Total Ringless (ACTIVITY, NUMBER)\n- `LIST` — List (CONTACT, LIST)\n- `SEGMENT` — Segment (SEGMENTS, SEGMENT)\n\nCustom fields: use the key from your account with `type=CUSTOM`. Example: `company_name` (CUSTOM, TEXT).",
            "example": "FIRST_NAME"
          },
          "value": {
            "type": "string",
            "description": "Primary comparison value. Multi-value conditions (IN, CONTAINS_ANY, …) are comma-separated.",
            "example": "Jane"
          },
          "valueExt": {
            "type": "string",
            "description": "Second bound for BETWEEN / NOT_BETWEEN date filters. Omit otherwise."
          },
          "dataType": {
            "type": "string",
            "description": "Must match the field data type. For custom fields use the custom field type.",
            "enum": [
              "LIST",
              "SEGMENT",
              "PHONE",
              "TEXT",
              "URL",
              "BOOLEAN",
              "NUMBER",
              "CURRENCY",
              "SELECT",
              "DATE_TIME",
              "DATE"
            ]
          },
          "type": {
            "type": "string",
            "description": "CONTACT, ACTIVITY, LOOKUP, or SEGMENTS for built-in fields. CUSTOM for a custom field key.",
            "enum": [
              "CONTACT",
              "CUSTOM",
              "ACTIVITY",
              "LOOKUP",
              "SEGMENTS"
            ]
          },
          "condition": {
            "type": "string",
            "description": "Operator for this field. Allowed operators depend on dataType.",
            "enum": [
              "EXISTS",
              "NOT_EXISTS",
              "IN",
              "NOT_IN",
              "CONTAINS_ANY",
              "CONTAINS_NONE",
              "STARTS_WITH_ANY",
              "ENDS_WITH_ANY",
              "BEFORE",
              "ON",
              "AFTER",
              "BETWEEN",
              "NOT_BETWEEN",
              "EQ",
              "NOT_EQ",
              "LESS",
              "LESS_EQ",
              "GREATER",
              "GREATER_EQ"
            ]
          },
          "orIndex": {
            "type": "integer",
            "format": "int32",
            "description": "OR group. Same orIndex values are ANDed; different orIndex values are ORed.",
            "example": 0
          },
          "andIndex": {
            "type": "integer",
            "format": "int32",
            "description": "Position inside the OR group. Must be unique together with orIndex.",
            "example": 0
          }
        }
      },
      "FilterValue": {
        "type": "object",
        "description": "Audience selector. Combine list/contact/segment IDs with either filters or sourceFilters, not both.",
        "example": {
          "listIds": [
            1
          ],
          "sourceFilters": [
            [
              {
                "field": "STATUS",
                "type": "CONTACT",
                "dataType": "SELECT",
                "condition": "IN",
                "value": "Active",
                "orIndex": 0,
                "andIndex": 0
              },
              {
                "field": "company_name",
                "type": "CUSTOM",
                "dataType": "TEXT",
                "condition": "CONTAINS_ANY",
                "value": "Acme",
                "orIndex": 0,
                "andIndex": 1
              }
            ]
          ]
        },
        "properties": {
          "sourceFilters": {
            "type": "array",
            "description": "Grouped filters. Each inner list is a group; groups are ORed. Inside a group, same orIndex values are ANDed. Do not send together with filters.",
            "items": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/Filter"
              }
            }
          },
          "filters": {
            "type": "array",
            "description": "Flat filter list. AND/OR is expressed with orIndex/andIndex. Do not send together with sourceFilters.",
            "items": {
              "$ref": "#/components/schemas/Filter"
            }
          },
          "contactIds": {
            "type": "array",
            "description": "Explicit contact IDs to include.",
            "items": {
              "type": "integer",
              "format": "int64"
            },
            "uniqueItems": true
          },
          "listIds": {
            "type": "array",
            "description": "Contact list IDs to include.",
            "items": {
              "type": "integer",
              "format": "int64"
            },
            "uniqueItems": true
          },
          "segmentIds": {
            "type": "array",
            "description": "Segment IDs to include.",
            "items": {
              "type": "integer",
              "format": "int64"
            },
            "uniqueItems": true
          }
        }
      },
      "ActiveContactsCountRequest": {
        "type": "object",
        "properties": {
          "filterValue": {
            "$ref": "#/components/schemas/FilterValue"
          },
          "type": {
            "type": "string",
            "enum": [
              "SMS",
              "Voice",
              "Ringless",
              "None"
            ]
          }
        }
      },
      "AssetResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "originalFileName": {
            "type": "string"
          },
          "sourceUrl": {
            "type": "string"
          },
          "compressedUrl": {
            "type": "string"
          },
          "previewUrl": {
            "type": "string"
          },
          "contentType": {
            "type": "string"
          },
          "extension": {
            "type": "string"
          },
          "sourceSize": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "AssetsResponse": {
        "type": "object",
        "properties": {
          "uploaded": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AssetResponse"
            }
          },
          "failed": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FailedAssetResponse"
            }
          },
          "failedMessage": {
            "type": "string"
          }
        }
      },
      "FailedAssetResponse": {
        "type": "object",
        "properties": {
          "fileName": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          }
        }
      },
      "UploadAssetRequest": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          }
        }
      },
      "ListingSearch": {
        "type": "object",
        "properties": {
          "searchPattern": {
            "type": "string"
          },
          "excludedListIds": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int64"
            }
          }
        }
      },
      "PageResponseListResponse": {
        "type": "object",
        "properties": {
          "content": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ListResponse"
            }
          },
          "pageNumber": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "total": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "ContactStatisticsResponse": {
        "type": "object",
        "properties": {
          "totalCount": {
            "type": "integer",
            "format": "int64"
          },
          "activeCount": {
            "type": "integer",
            "format": "int64"
          },
          "inactiveCount": {
            "type": "integer",
            "format": "int64"
          },
          "invalidCount": {
            "type": "integer",
            "format": "int64"
          },
          "archivedCount": {
            "type": "integer",
            "format": "int64"
          },
          "unsubscribedCount": {
            "type": "integer",
            "format": "int64"
          },
          "dncCount": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "ListContactSearchResult": {
        "type": "object",
        "properties": {
          "listings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ListResponse"
            }
          },
          "totalListings": {
            "type": "integer",
            "format": "int32"
          },
          "contacts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContactLightResponse"
            }
          },
          "totalContacts": {
            "type": "integer",
            "format": "int32"
          },
          "segments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SegmentResponse"
            }
          },
          "totalSegments": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "SegmentResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "name": {
            "type": "string"
          },
          "filterValue": {
            "$ref": "#/components/schemas/FilterValue"
          }
        }
      },
      "PageResponseContactCardResponse": {
        "type": "object",
        "properties": {
          "content": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContactCardResponse"
            }
          },
          "pageNumber": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "total": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "PageResponseAudioItem": {
        "type": "object",
        "properties": {
          "content": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AudioItem"
            }
          },
          "pageNumber": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "total": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "PageResponseAssetResponse": {
        "type": "object",
        "properties": {
          "content": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AssetResponse"
            }
          },
          "pageNumber": {
            "type": "integer",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "format": "int32"
          },
          "total": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "MessageResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          }
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "description": "Personal Access Token. Send as: Authorization: Bearer pat_v1.<token>",
        "scheme": "bearer",
        "bearerFormat": "PAT"
      }
    }
  }
}