{
  "info": {
    "name": "5c SMS & Dingo Mail API",
    "_postman_id": "8f4d2a1c-3b6e-4f7a-9c0d-5e8b1a2c3d4e",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "description": "# 5c SMS & Dingo Mail API\n\nOne API for business messaging across two channels: SMS through **5c SMS** and email through **Dingo Mail**. Send and track SMS, hold two-way conversations, read inbound messages, and manage opt-outs, sender IDs and virtual numbers. Send transactional and bulk email from your own verified sending domains, with delivery status on every message. Endpoints are secure, JSON over HTTPS, and grouped in the sidebar by area.\n\n## Getting started\n\n**Step 1: Generate your API key.**\n1. Go to https://www.5centsms.com.au/dashboard/api\n2. In **API Key Management**, set a **Key Alias** to identify the key.\n3. Click **Create New API Key**.\n4. Copy the generated **Key ID** and **Key Secret**.\n\nThe same key authenticates both the 5c SMS endpoints and the Dingo Mail email endpoints.\n\n> **Important:** Store your credentials securely. The Key Secret is shown only once and cannot be retrieved again.\n\n**Step 2: Send your first SMS.**\n```bash\ncurl -X POST {{base_url_sms}}/sms \\\n  -H \"Authorization: Bearer Paste Key ID here:Paste Key Secret here\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"sender\": \"0404123123\",\n    \"to\": \"Paste recipient number here\",\n    \"message\": \"Hello World\"\n  }'\n```\n\n**Step 3: Send your first email.**\n```bash\ncurl -X POST {{base_url_dingo}}/email \\\n  -H \"Authorization: Bearer Paste Key ID here:Paste Key Secret here\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"SenderEmail\": \"news@mail.example.com\",\n    \"SenderName\": \"Example\",\n    \"Subject\": \"Hello\",\n    \"Text\": \"Hello World\",\n    \"Recipient\": \"Paste recipient email here\"\n  }'\n```\n\nEmail sends from a verified sending domain. Register one with **Create Domain** (under Email Domains) or in the dashboard, then use any address at that domain as the `SenderEmail`.\n\n## Authentication\n\nEvery request authenticates with your `key-id` and `key-secret`. Set them once as the `key_id` / `key_secret` collection variables (under the collection's **Variables** tab) and they apply to every request here.\n\nSend the pair in the `Authorization` header as a `Bearer` token, id and secret joined by a colon. This collection is preconfigured to do this on every request:\n\n```bash\ncurl -X POST {{base_url_sms}}/sms \\\n  -H \"Authorization: Bearer your-key-id:your-key-secret\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{ \"sender\": \"0404123123\", \"to\": \"0412333555\", \"message\": \"Hello World\" }'\n```\n\nAll requests must use **HTTPS** — a plain HTTP request is rejected with `400 HTTPS Required`.\n\n## Responses & errors\n\nEvery response is JSON and carries an `error` field. The HTTP status follows from it:\n\n- **HTTP 200** — success; `error` is an empty string (`\"\"`).\n- **HTTP 400** — the request failed; the reason is in `error`.\n- **HTTP 401** — authentication failed (see the table below).\n- **HTTP 503** — the API is in maintenance; retry shortly.\n\nAn unsupported method/path combination returns `Unsupported method. Please see our API Docs`.\n\n**Authentication errors (HTTP 401):**\n\n| Error | Cause |\n| --- | --- |\n| `Failed (Invalid Key ID)` | The `key-id` is missing or not recognised. |\n| `Failed (Invalid Key Secret)` | The `key-secret` does not match the key. |\n| `Failed (Invalid API ID or Key)` | The key id/secret pair is invalid. |\n| `Failed (Invalid Username or API Key)` | The key id/secret pair failed verification. |\n\n## API hosts\n\nTwo base URLs back this collection, preset as variables:\n\n- `{{base_url_sms}}` (5c SMS): SMS, Conversations, Account, Logins, Sender IDs, Virtual Numbers.\n- `{{base_url_dingo}}` (Dingo Mail): Email and Email Domains.\n\n## Pagination\n\nList endpoints return results **newest-first, one page at a time**. To fetch the next page, pass the **last item's `id`** as the `after` query parameter. `after` is a 24-character hex cursor (a MongoDB ObjectId), **not** an offset or page number.\n\nEach list response includes `next_page` — a ready-to-use relative path already containing the `after` value for the following page — and `count` (items on the current page). Follow `next_page` until it is absent or empty.\n\n`next_page` is a **root-relative** path beginning with `/` (for example `/api/v5/sms?after=...`). Resolve it against the API host (scheme + host of the base URL), not against the current request path, then re-send with the same credentials.\n\nCursor-paginated endpoints (Conversations) return `next_cursor` instead: pass it back as the `before` parameter, and stop when it is null.\n\nPage sizes are fixed per endpoint:\n\n| Endpoint | Page size |\n| --- | --- |\n| List Emails | 20 (override with `limit`, 1–100) |\n| List Inbound Messages | 50 |\n| List Opt-outs | 1000 |\n\nA malformed `after` returns HTTP 400 — `Failed (Invalid Page)` on the SMS / Inbox / Opt-out endpoints, `Invalid after parameter` on List Emails (which also rejects a bad `limit` with `Invalid limit parameter`). Logins, Sender IDs, Virtual Numbers, and Email Domains return full unpaginated lists.\n\n## Message status codes\n\nThe `status` field on a message maps to a human-readable `status_text`. For the full list of status codes and their meanings, see [Message Status List](https://www.5centsms.com.au/web/status).\n\n## Data retention\n\nMessage data is retained for 365 days from the date of processing, after which it is permanently purged. Contact support if you require a different retention timeframe.\n\n## Using Postman\n\nDownload this collection and import it into Postman (**Import → File**, or paste the raw link). Set the `key_id` and `key_secret` collection variables once under the collection's **Variables** tab, then open any request and click **Send**. Each request's **Documentation** pane (the right-hand panel) shows its parameters, response fields, and errors."
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{key_id}}:{{key_secret}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "base_url_sms",
      "value": "https://www.5centsms.com.au/api/v5"
    },
    {
      "key": "base_url_dingo",
      "value": "https://api.dingomail.com.au/api/v5"
    },
    {
      "key": "key_id",
      "value": ""
    },
    {
      "key": "key_secret",
      "value": ""
    }
  ],
  "item": [
    {
      "name": "SMS",
      "item": [
        {
          "name": "Send SMS",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/sms",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "sms"
              ]
            },
            "description": "Send a single SMS to one or more recipients.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `sender` | string | Yes | Sender ID. Max 13 characters; max 11 if alphanumeric ([0-9a-zA-Z] only). |\n| `to` | string | Yes | Recipient number(s), comma-separated. International or 04 format. |\n| `message` | string | Yes | Message content. Hex-encoded UTF-16 when `unicode` is true. |\n| `test` | boolean | No | Simulate the send — no SMS delivered, no credits charged. Default false. |\n| `unicode` | boolean | No | Send as UTF-16; `message` must be hex-encoded. Must be enabled on your account. Deprecated for new accounts; use a Unified Virtual Number for rich text messaging. Default false. |\n| `schedule` | integer | No | UNIX epoch seconds for future delivery, max 356 days ahead. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `messages` | array | One entry per recipient. |\n| `messages[].destination` | string | Recipient number. |\n| `messages[].id` | string | Message id. |\n| `messages[].status` | integer | Status code (see Introduction). |\n| `messages[].status_text` | string | Human-readable status. |\n| `messages[].credits` | number | Credits charged. |\n| `messages[].schedule` | integer | Scheduled epoch — only when the message is scheduled (status 1005). |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Failed (Invalid Sender ID)` | 400 | `sender` missing, >13 chars, or alphanumeric >11 chars / invalid characters. |\n| `Failed (Invalid Destination)` | 400 | `to` missing. |\n| `Failed (Invalid Message)` | 400 | `message` missing. |\n\n#### Notes\n- With `unicode`, emoji and non-GSM text are supported; e.g. `Testing🎉` hex-encodes to `00540065007300740069006E0067D83CDF89`.\n- Use `test: true` to verify integration without sending or charging.",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"sender\": \"0404123123\",\n  \"to\": \"0412333555\",\n  \"message\": \"Hello World\",\n  \"test\": false,\n  \"unicode\": false,\n  \"schedule\": 0\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"messages\": [\n    {\n      \"destination\": \"0412333555\",\n      \"id\": \"683554c596937cc4b90f5cf7\",\n      \"status\": 1011,\n      \"status_text\": \"Sending...\",\n      \"credits\": 1\n    }\n  ]\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Failed (Invalid Sender ID)\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "List Sent SMS",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/sms",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "sms"
              ],
              "query": [
                {
                  "key": "after",
                  "value": "",
                  "description": "24-hex cursor — the `id` of the last message on the previous page.",
                  "disabled": true
                }
              ]
            },
            "description": "List your sent messages, newest first.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `messages` | array | Sent messages this page. |\n| `messages[].destination` | string | Recipient number. |\n| `messages[].sender` | string | Sender ID the message was sent from (mobile number, virtual number, or alphanumeric sender ID). |\n| `messages[].id` | string | Message id. |\n| `messages[].status` | integer | Status code (see Introduction). |\n| `messages[].status_text` | string | Human-readable status. |\n| `messages[].message_text` | string | Message content. |\n| `messages[].credits` | number | Credits charged. |\n| `messages[].send_timestamp` | integer | Epoch seconds when sent. |\n| `messages[].delivery_timestamp` | integer | Epoch seconds when delivery confirmed. |\n| `messages[].delivery_network` | string | Delivering network, when known. |\n| `next_page` | string | Relative path for the next page. Omitted when there are no further results. |\n| `count` | integer | Messages on this page. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Failed (Invalid Page)` | 400 | `after` is not a valid 24-hex cursor. |\n\n#### Notes\n- See **Pagination** in the Introduction for the `after` cursor convention.\n- `next_page` is omitted when there are no further results.",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"messages\": [\n    {\n      \"destination\": \"0412333555\",\n      \"sender\": \"5CENTSMS\",\n      \"id\": \"683554c596937cc4b90f5cf7\",\n      \"status\": 1002,\n      \"status_text\": \"Sent (Delivery Confirmed)\",\n      \"message_text\": \"Hello World\",\n      \"credits\": 1,\n      \"send_timestamp\": 1717000000,\n      \"delivery_timestamp\": 1717000020,\n      \"delivery_network\": \"Telstra\"\n    },\n    {\n      \"destination\": \"0412333556\",\n      \"sender\": \"0428000000\",\n      \"id\": \"683554c596937cc4b90f5cf6\",\n      \"status\": 1001,\n      \"status_text\": \"Sent\",\n      \"message_text\": \"Your verification code is 4821\",\n      \"credits\": 1,\n      \"send_timestamp\": 1716999900,\n      \"delivery_timestamp\": 0,\n      \"delivery_network\": \"Optus\"\n    },\n    {\n      \"destination\": \"0412333557\",\n      \"sender\": \"SHOPCO\",\n      \"id\": \"683554c596937cc4b90f5cf5\",\n      \"status\": 1002,\n      \"status_text\": \"Sent (Delivery Confirmed)\",\n      \"message_text\": \"Your order has shipped\",\n      \"credits\": 1,\n      \"send_timestamp\": 1716999800,\n      \"delivery_timestamp\": 1716999830,\n      \"delivery_network\": \"Vodafone\"\n    }\n  ],\n  \"next_page\": \"/api/v5/sms?after=683554c596937cc4b90f5cf5\",\n  \"count\": 3\n}"
            },
            {
              "name": "200 OK (Last Page)",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"messages\": [\n    {\n      \"destination\": \"0412333558\",\n      \"sender\": \"5CENTSMS\",\n      \"id\": \"683554c596937cc4b90f5cf4\",\n      \"status\": 1002,\n      \"status_text\": \"Sent (Delivery Confirmed)\",\n      \"message_text\": \"Appointment reminder\",\n      \"credits\": 1,\n      \"send_timestamp\": 1716999700,\n      \"delivery_timestamp\": 1716999730,\n      \"delivery_network\": \"Telstra\"\n    }\n  ],\n  \"count\": 1\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Get SMS Status",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/sms/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "sms",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Message id."
                }
              ]
            },
            "description": "Fetch the current status and details of a single sent message.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `message` | object | The message (same fields as List Sent SMS). |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Failed (Unauthorised)` | 400 | Message not found, or not owned by this account. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"message\": {\n    \"destination\": \"0412333555\",\n    \"sender\": \"5CENTSMS\",\n    \"id\": \"683554c596937cc4b90f5cf7\",\n    \"status\": 1002,\n    \"status_text\": \"Sent (Delivery Confirmed)\",\n    \"message_text\": \"Hello World\",\n    \"credits\": 1,\n    \"send_timestamp\": 1717000000,\n    \"delivery_timestamp\": 1717000020,\n    \"delivery_network\": \"Telstra\"\n  }\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Cancel / Delete SMS",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/sms/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "sms",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Message id."
                }
              ]
            },
            "description": "Cancel a still-scheduled message (status 1005), or delete a sent message's record.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Failed (Unauthorised)` | 400 | Message not found, or not owned by this account. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "List Inbound Messages",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/inbox",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "inbox"
              ],
              "query": [
                {
                  "key": "after",
                  "value": "",
                  "description": "24-hex cursor - the `id` of the last message on the previous page. Returns messages older than that id, matching this list's newest-first order.",
                  "disabled": true
                },
                {
                  "key": "include_archived",
                  "value": "1",
                  "description": "Optional. Set to 1 to include archived messages. Archived messages are excluded by default.",
                  "disabled": true
                }
              ]
            },
            "description": "List inbound (received) messages, newest first (50 per page).\n\n#### Query parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `after` | string | No | 24-hex cursor - the `id` of the last message on the previous page. Returns messages older than that id. |\n| `include_archived` | boolean | No | Set to `1` to include archived messages. Excluded by default. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `messages` | array | Inbound messages this page. |\n| `messages[].id` | string | Inbound message id. |\n| `messages[].to` | string | Your number that received it. |\n| `messages[].from` | string | Sender number. |\n| `messages[].message` | string | Message content. |\n| `messages[].date` | integer | Epoch seconds received. |\n| `messages[].contact_name` | string | Matched contact name, when known. |\n| `messages[].archived` | boolean | True when the account has archived this message. Only ever `true` when `include_archived` is set. |\n| `next_page` | string | Relative path for the next page. Always present on this endpoint - stop paging when `messages` is empty (`count` is 0). It carries `include_archived` when that flag was set. |\n| `count` | integer | Messages on this page. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Failed (Invalid Page)` | 400 | `after` is not a valid 24-hex cursor. |\n\n#### Notes\n- Page size is fixed at 50. Follow `next_page` (which carries the `after` cursor) until a page comes back with an empty `messages` array.\n- The list is newest-first and `after` pages backwards through it: each page returns the 50 messages older than the cursor.\n- Archived messages are excluded from this list. Pass `include_archived=1` to include them. Archive with `POST /inbox/{id}`. Archiving cannot be reversed.\n- Archiving does not delete: an archived message keeps its text, its attachments, and its place in the conversation, and its 356-day retention is unchanged.",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"messages\": [\n    {\n      \"id\": \"683554c596937cc4b90f5cf7\",\n      \"to\": \"0400000000\",\n      \"from\": \"0412333555\",\n      \"message\": \"STOP\",\n      \"date\": 1717000000,\n      \"contact_name\": \"Jane\",\n      \"archived\": false\n    },\n    {\n      \"id\": \"683554c596937cc4b90f5cf3\",\n      \"to\": \"0400000000\",\n      \"from\": \"0412999888\",\n      \"message\": \"Yes, please book me in\",\n      \"date\": 1716999500,\n      \"contact_name\": \"Tom\",\n      \"archived\": false\n    }\n  ],\n  \"next_page\": \"/api/v5/inbox?after=683554c596937cc4b90f5cf3\",\n  \"count\": 2\n}"
            },
            {
              "name": "200 OK (Including Archived)",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"messages\": [\n    {\n      \"id\": \"683554c596937cc4b90f5cf7\",\n      \"to\": \"0400000000\",\n      \"from\": \"0412333555\",\n      \"message\": \"STOP\",\n      \"date\": 1717000000,\n      \"contact_name\": \"Jane\",\n      \"archived\": true\n    },\n    {\n      \"id\": \"683554c596937cc4b90f5cf3\",\n      \"to\": \"0400000000\",\n      \"from\": \"0412999888\",\n      \"message\": \"Yes, please book me in\",\n      \"date\": 1716999500,\n      \"contact_name\": \"Tom\",\n      \"archived\": false\n    }\n  ],\n  \"next_page\": \"/api/v5/inbox?after=683554c596937cc4b90f5cf3&include_archived=1\",\n  \"count\": 2\n}"
            },
            {
              "name": "200 OK (Last Page)",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"messages\": [],\n  \"next_page\": \"/api/v5/inbox?after=\",\n  \"count\": 0\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Delete Inbound Message",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/inbox/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "inbox",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Inbound message id."
                }
              ]
            },
            "description": "Delete a single inbound message record.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Failed (Invalid message ID format)` | 400 | The `id` path segment is not a 24-character hexadecimal id. |\n| `Failed (Unauthorised)` | 400 | Message not found, or not owned by this account. |\n\n#### Notes\n- This permanently removes the message document. To keep the message but hide it from `GET /inbox`, use `POST /inbox/{id}` with `archived: true` instead.",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Archive Inbound Message",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "url": {
              "raw": "{{base_url_sms}}/inbox/:id",
              "host": [ "{{base_url_sms}}" ],
              "path": [ "inbox", ":id" ],
              "variable": [
                { "key": "id", "value": "", "description": "Inbound message id." }
              ]
            },
            "description": "Archive one received message. Archiving hides the message from `GET /inbox` unless that call passes `include_archived=1`; it never deletes the message or its attachments, does not change its 356-day retention, and leaves it visible in the conversation view.\n\n**Archiving is permanent.** There is no unarchive operation, on this endpoint or in the dashboard. Sending `archived: false` returns `Unarchiving is not supported`.\n\n#### Request body\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `key-id` | string | Yes | API key id (see intro auth). |\n| `key-secret` | string | Yes | API key secret (see intro auth). |\n| `archived` | boolean | Yes | Must be truthy (`true`, `1`, `\"true\"`). A falsy value is rejected - archiving cannot be reversed. |\n\n#### Path parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `id` | string | Yes | 24-hex inbound message id. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `message` | string | `Inbound message archived`. |\n| `id` | string | The inbound message id acted on. |\n| `archived` | boolean | Always `true` on success. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid inbound message ID` | 400 | `id` is not a valid 24-hex id. |\n| `archived Required. Please see our API Docs` | 400 | The body has no `archived` field. |\n| `Unarchiving is not supported` | 400 | `archived` was sent as `false`, `0`, `\"false\"`, or `null`. |\n| `Failed (Unauthorised)` | 400 | No such inbound message, or not owned by this account. |\n| `Unsupported method. Please see our API Docs` | 400 | POSTed to `/inbox` with no id. |\n\n#### Notes\n- Idempotent: re-archiving an already-archived message succeeds and returns the same body. It refreshes the stored archive timestamp to the time of the latest request.\n- Archiving is free and does not touch the message balance.\n- To remove the message entirely instead, use `DELETE /inbox/{id}`.",
            "body": {
              "mode": "raw",
              "options": { "raw": { "language": "json" } },
              "raw": "{\n  \"key-id\": \"{{key_id}}\",\n  \"key-secret\": \"{{key_secret}}\",\n  \"archived\": true\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"message\": \"Inbound message archived\",\n  \"id\": \"683554c596937cc4b90f5cf7\",\n  \"archived\": true\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Unarchiving is not supported\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "List Opt-outs",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/optouts",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "optouts"
              ],
              "query": [
                {
                  "key": "after",
                  "value": "",
                  "description": "24-hex cursor — the `id` of the last record on the previous page.",
                  "disabled": true
                }
              ]
            },
            "description": "List numbers that have opted out, newest first (1000 per page).\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `numbers` | array | Opted-out numbers this page. |\n| `numbers[].id` | string | Opt-out record id. |\n| `numbers[].number` | string | Opted-out number. |\n| `numbers[].timestamp` | integer | Epoch seconds of opt-out. |\n| `count` | integer | Records on this page. |\n| `next_page` | string | Relative path for the next page. Always present on this endpoint — stop paging when `numbers` is empty (`count` is 0). |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Failed (Invalid Page)` | 400 | `after` is not a valid 24-hex cursor. |\n\n#### Notes\n- Page size is fixed at 1000. Follow `next_page` (which carries the `after` cursor) until a page comes back with an empty `numbers` array.",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"numbers\": [\n    {\n      \"id\": \"683554c596937cc4b90f5cf7\",\n      \"number\": \"0412333555\",\n      \"timestamp\": 1717000000\n    },\n    {\n      \"id\": \"683554c596937cc4b90f5cf2\",\n      \"number\": \"0412333777\",\n      \"timestamp\": 1716999000\n    }\n  ],\n  \"count\": 2,\n  \"next_page\": \"/api/v5/optouts?after=683554c596937cc4b90f5cf2\"\n}"
            },
            {
              "name": "200 OK (Last Page)",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"numbers\": [],\n  \"count\": 0,\n  \"next_page\": \"/api/v5/optouts?after=\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Delete Opt-out",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/optouts/:number",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "optouts",
                ":number"
              ],
              "variable": [
                {
                  "key": "number",
                  "value": "",
                  "description": "The opted-out number to remove."
                }
              ]
            },
            "description": "Remove a number from your opt-out list.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `message` | string | Confirmation message. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"message\": \"Number removed.\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "List Status Codes",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/statuslist",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "statuslist"
              ]
            },
            "description": "Return the full catalogue of message status codes and their descriptions. The list is global (not account-specific) and matches the codes returned in the `status` field of `GET /sms` and `GET /sms/{id}` and the descriptions used in the Dashboard.\n\nAuthentication is still required (see the intro's **Authentication** section) so the call is rate-limited and logged like every other v5 endpoint.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `status_codes` | array | One object per status code. |\n| `status_codes[].code` | number | Numeric status code (e.g. `1002`). |\n| `status_codes[].description` | string | Human-readable description (e.g. `Sent (Delivery Confirmed)`). |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Unsupported method. Please see our API Docs` | 400 | The endpoint was called with `POST` or `DELETE`. |\n\nAuthentication errors are documented once in the collection intro (401 auth-error table).",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"status_codes\": [\n    { \"code\": 1000, \"description\": \"Sending... (Queued)\" },\n    { \"code\": 1001, \"description\": \"Sent\" },\n    { \"code\": 1002, \"description\": \"Sent (Delivery Confirmed)\" }\n  ]\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Conversations",
      "item": [
        {
          "name": "List Conversations",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/conversations?per_page=50",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "conversations"
              ],
              "query": [
                {
                  "key": "before",
                  "value": "",
                  "disabled": true,
                  "description": "Cursor from a previous response's next_cursor. Omit for the first page."
                },
                {
                  "key": "per_page",
                  "value": "50",
                  "description": "Page size, max 200. Default 50."
                },
                {
                  "key": "q",
                  "value": "",
                  "disabled": true,
                  "description": "Digit search on the contact number."
                },
                {
                  "key": "replies",
                  "value": "1",
                  "disabled": true,
                  "description": "Set to 1 to return only conversations that have an inbound reply."
                },
                {
                  "key": "unread",
                  "value": "1",
                  "disabled": true,
                  "description": "Set to 1 to return only unread conversations."
                }
              ]
            },
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            },
            "description": "List the account's two-way SMS conversations, newest activity first, cursor-paginated. Requires Conversations (threads) enabled and at least one virtual mobile number (VMN).\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `conversations` | array | One entry per conversation, newest activity first. |\n| `conversations[].id` | string | Conversation id. |\n| `conversations[].remote_number` | string | Contact number, normalised to `61` international form. |\n| `conversations[].contact_name` | string | Matched contact name, or empty. |\n| `conversations[].last_message_at` | integer | Epoch seconds of the latest message. |\n| `conversations[].unread` | boolean | Unread flag. |\n| `conversations[].has_inbound` | boolean | True once the contact has replied. |\n| `conversations[].last_local_number` | string | The VMN this thread is on. |\n| `conversations[].created_at` | integer | Epoch seconds the conversation began. |\n| `next_cursor` | string or null | Pass as `before` for the next page; null on the last page. |\n| `count` | integer | Conversations on this page. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Conversations are not enabled for this account. Enable Conversations in your 5cSMS dashboard settings, or contact support to turn on two-way messaging.` | 400 | Account lacks the `ENABLE_THREADS` flag. Response also carries `error_code: \"threads_disabled\"`. |\n| `Conversations require a dedicated virtual mobile number (VMN). Add a VMN in your 5cSMS dashboard under Virtual Numbers, then inbound replies will thread automatically.` | 400 | Threads on but the account has no VMN. Response also carries `error_code: \"no_vmn\"`. |\n| `Failed (Method Not Supported)` | 400 | A POST or DELETE was sent to any `/conversations` route. The endpoint is read-only. |\n\n#### Notes\n- Gate failures return an extra `error_code` field (`threads_disabled` or `no_vmn`) so an integrator can branch programmatically.\n- Follow `next_cursor` (passed back as the `before` parameter) until it is null.\n- `q` matches digits in the remote number; `replies=1` and `unread=1` are independent filters.\n- To send, use `POST /api/v5/sms`. Replies thread into the conversation automatically."
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"conversations\": [\n    {\n      \"id\": \"66b0a1c2d3e4f5a6b7c8d9e0\",\n      \"remote_number\": \"61412345678\",\n      \"contact_name\": \"Jane Smith\",\n      \"last_message_at\": 1749600120,\n      \"unread\": true,\n      \"has_inbound\": true,\n      \"last_local_number\": \"61480000000\",\n      \"created_at\": 1749000000\n    }\n  ],\n  \"next_cursor\": \"1749600120_66b0a1c2d3e4f5a6b7c8d9e0\",\n  \"count\": 1\n}"
            },
            {
              "name": "200 OK (Last Page)",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"conversations\": [\n    {\n      \"id\": \"66a90b1c2d3e4f5a6b7c8d90\",\n      \"remote_number\": \"61412000111\",\n      \"contact_name\": \"\",\n      \"last_message_at\": 1748900000,\n      \"unread\": false,\n      \"has_inbound\": false,\n      \"last_local_number\": \"61480000000\",\n      \"created_at\": 1748900000\n    }\n  ],\n  \"next_cursor\": null,\n  \"count\": 1\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Conversations are not enabled for this account. Enable Conversations in your 5cSMS dashboard settings, or contact support to turn on two-way messaging.\",\n  \"error_code\": \"threads_disabled\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Resolve Conversation by Number",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/conversations?number=0412345678",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "conversations"
              ],
              "query": [
                {
                  "key": "number",
                  "value": "0412345678",
                  "description": "Required. Recipient MSISDN in 04..., +61..., or 61... form; normalised to 61 international form."
                }
              ]
            },
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            },
            "description": "Resolve a single conversation by the remote phone number. The number is normalised to `61` international form, so `04...`, `+61...`, and `61...` inputs all resolve.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `conversation` | object or null | The matching conversation summary (same fields as a List entry, plus `contact_name`), or `null` when the number has no thread. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Conversations are not enabled for this account. Enable Conversations in your 5cSMS dashboard settings, or contact support to turn on two-way messaging.` | 400 | Account lacks the `ENABLE_THREADS` flag. Response also carries `error_code: \"threads_disabled\"`. |\n| `Conversations require a dedicated virtual mobile number (VMN). Add a VMN in your 5cSMS dashboard under Virtual Numbers, then inbound replies will thread automatically.` | 400 | Threads on but the account has no VMN. Response also carries `error_code: \"no_vmn\"`. |\n\n#### Notes\n- A number with no conversation returns `{\"error\": \"\", \"conversation\": null}`. This is a success, not an error.\n- Gate failures return an extra `error_code` field (`threads_disabled` or `no_vmn`)."
          },
          "response": [
            {
              "name": "200 OK (resolved)",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"conversation\": {\n    \"id\": \"66b0a1c2d3e4f5a6b7c8d9e0\",\n    \"remote_number\": \"61412345678\",\n    \"contact_name\": \"Jane Smith\",\n    \"last_message_at\": 1749600120,\n    \"unread\": true,\n    \"has_inbound\": true,\n    \"last_local_number\": \"61480000000\",\n    \"created_at\": 1749000000\n  }\n}"
            },
            {
              "name": "200 OK (no thread)",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"conversation\": null\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Get Conversation Messages",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/conversations/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "conversations",
                ":id"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "50",
                  "disabled": true,
                  "description": "Page size, 1 to 100. Default 50."
                }
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "66b0a1c2d3e4f5a6b7c8d9e0",
                  "description": "Conversation id."
                }
              ]
            },
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            },
            "description": "Fetch the conversation summary plus the most recent page of messages (oldest to newest within the page). Opening a conversation marks it read.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `conversation` | object | Conversation summary, including `contact_name`. |\n| `messages` | array | Messages, oldest to newest within the page. |\n| `messages[].id` | string | Message id. |\n| `messages[].message` | string | Message text. |\n| `messages[].timestamp` | integer | Epoch seconds. |\n| `messages[].type` | string | `MT` (sent) or `MO` (received). |\n| `messages[].status` | integer or null | Delivery status code (MT only). See the message status table in the Introduction. |\n| `messages[].status_text` | string | Human-readable status, e.g. \"Delivered\" (MT only). |\n| `messages[].scheduled` | boolean | Present and true when the message is scheduled (MT only). |\n| `messages[].cancelled` | boolean | Present and true when the message was cancelled (MT only). |\n| `messages[].cancellable` | boolean | Present and true when the message can still be cancelled (MT only). |\n| `messages[].images` | array | Image URLs (MMS only). |\n| `has_more` | boolean | True when older messages remain (page back with `action=older`). |\n| `oldest_mo_ts` | integer | Oldest received-message watermark on this page (use as `before_mo`). |\n| `oldest_mt_ts` | integer | Oldest sent-message watermark on this page (use as `before_mt`). |\n| `newest_mo_ts` | integer | Newest received-message watermark (use as `since_mo` when polling). |\n| `newest_mt_ts` | integer | Newest sent-message watermark (use as `since_mt` when polling). |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Conversations are not enabled for this account. Enable Conversations in your 5cSMS dashboard settings, or contact support to turn on two-way messaging.` | 400 | Account lacks the `ENABLE_THREADS` flag. Response also carries `error_code: \"threads_disabled\"`. |\n| `Conversations require a dedicated virtual mobile number (VMN). Add a VMN in your 5cSMS dashboard under Virtual Numbers, then inbound replies will thread automatically.` | 400 | Threads on but the account has no VMN. Response also carries `error_code: \"no_vmn\"`. |\n| `Failed (Conversation Not Found)` | 400 | The `id` was not found or is not owned by this account. |\n\n#### Notes\n- Side effect: opening a conversation marks it read (`unread` becomes false).\n- Page back through history with the **Page Older Messages** request, and fetch new messages with the **Poll Conversation** request.\n- To send a reply, use `POST /api/v5/sms`. Replies thread into the conversation automatically."
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"conversation\": {\n    \"id\": \"66b0a1c2d3e4f5a6b7c8d9e0\",\n    \"remote_number\": \"61412345678\",\n    \"contact_name\": \"Jane Smith\",\n    \"last_message_at\": 1749600120,\n    \"unread\": false,\n    \"has_inbound\": true,\n    \"last_local_number\": \"61480000000\",\n    \"created_at\": 1749000000\n  },\n  \"messages\": [\n    {\n      \"id\": \"66a0a1c2d3e4f5a6b7c8d9e0\",\n      \"message\": \"Your booking is confirmed\",\n      \"timestamp\": 1749600060,\n      \"type\": \"MT\",\n      \"status\": 1002,\n      \"status_text\": \"Sent (Delivery Confirmed)\"\n    },\n    {\n      \"id\": \"66a1a1c2d3e4f5a6b7c8d9e0\",\n      \"message\": \"Yes please\",\n      \"timestamp\": 1749600120,\n      \"type\": \"MO\"\n    }\n  ],\n  \"has_more\": false,\n  \"oldest_mo_ts\": 1749600120,\n  \"oldest_mt_ts\": 1749600060,\n  \"newest_mo_ts\": 1749600120,\n  \"newest_mt_ts\": 1749600060\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Failed (Conversation Not Found)\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Poll Conversation",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/conversations/:id?action=poll&since_mo=1749600120&since_mt=1749600060",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "conversations",
                ":id"
              ],
              "query": [
                {
                  "key": "action",
                  "value": "poll",
                  "description": "Required. Set to poll."
                },
                {
                  "key": "since_mo",
                  "value": "1749600120",
                  "description": "Required. Received-message watermark (epoch seconds); use the prior response's newest_mo_ts."
                },
                {
                  "key": "since_mt",
                  "value": "1749600060",
                  "description": "Required. Sent-message watermark (epoch seconds); use the prior response's newest_mt_ts."
                }
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "66b0a1c2d3e4f5a6b7c8d9e0",
                  "description": "Conversation id."
                }
              ]
            },
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            },
            "description": "Return only messages newer than the supplied watermarks. Use the `newest_mo_ts` and `newest_mt_ts` from the initial load (or the previous poll) as `since_mo` and `since_mt`. A poll that returns new messages marks the conversation read.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `messages` | array | Only messages newer than the watermarks (same message shape as **Get Conversation Messages**). |\n| `now` | integer | Server epoch seconds, for poll cadence. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Conversations are not enabled for this account. Enable Conversations in your 5cSMS dashboard settings, or contact support to turn on two-way messaging.` | 400 | Account lacks the `ENABLE_THREADS` flag. Response also carries `error_code: \"threads_disabled\"`. |\n| `Conversations require a dedicated virtual mobile number (VMN). Add a VMN in your 5cSMS dashboard under Virtual Numbers, then inbound replies will thread automatically.` | 400 | Threads on but the account has no VMN. Response also carries `error_code: \"no_vmn\"`. |\n| `Failed (Conversation Not Found)` | 400 | The `id` was not found or is not owned by this account. |\n| `Failed (Invalid Watermark)` | 400 | `since_mo` or `since_mt` is missing or not a digit string. |\n\n#### Notes\n- Side effect: a poll that returns one or more new messages marks the conversation read.\n- `since_mo` and `since_mt` must be integer epoch-second values."
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"messages\": [\n    {\n      \"id\": \"66a2a1c2d3e4f5a6b7c8d9e0\",\n      \"message\": \"On my way\",\n      \"timestamp\": 1749600300,\n      \"type\": \"MO\"\n    }\n  ],\n  \"now\": 1749600305\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Page Older Messages",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/conversations/:id?action=older&before_mo=1749600120&before_mt=1749600060",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "conversations",
                ":id"
              ],
              "query": [
                {
                  "key": "action",
                  "value": "older",
                  "description": "Required. Set to older."
                },
                {
                  "key": "before_mo",
                  "value": "1749600120",
                  "description": "Required. Use the prior response's oldest_mo_ts."
                },
                {
                  "key": "before_mt",
                  "value": "1749600060",
                  "description": "Required. Use the prior response's oldest_mt_ts."
                },
                {
                  "key": "limit",
                  "value": "50",
                  "disabled": true,
                  "description": "Page size, 1 to 100. Default 50."
                }
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "66b0a1c2d3e4f5a6b7c8d9e0",
                  "description": "Conversation id."
                }
              ]
            },
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            },
            "description": "Page back through history older than the supplied cursors. Use the `oldest_mo_ts` and `oldest_mt_ts` from the previous page as `before_mo` and `before_mt`.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `messages` | array | The older page (same message shape as **Get Conversation Messages**). |\n| `has_more` | boolean | True when still-older messages remain. |\n| `oldest_mo_ts` | integer | Oldest received-message watermark on this page (use as the next `before_mo`). |\n| `oldest_mt_ts` | integer | Oldest sent-message watermark on this page (use as the next `before_mt`). |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Conversations are not enabled for this account. Enable Conversations in your 5cSMS dashboard settings, or contact support to turn on two-way messaging.` | 400 | Account lacks the `ENABLE_THREADS` flag. Response also carries `error_code: \"threads_disabled\"`. |\n| `Conversations require a dedicated virtual mobile number (VMN). Add a VMN in your 5cSMS dashboard under Virtual Numbers, then inbound replies will thread automatically.` | 400 | Threads on but the account has no VMN. Response also carries `error_code: \"no_vmn\"`. |\n| `Failed (Conversation Not Found)` | 400 | The `id` was not found or is not owned by this account. |\n| `Failed (Invalid Watermark)` | 400 | `before_mo` or `before_mt` is missing or not a digit string. |\n\n#### Notes\n- This request does not mark the conversation read (unlike the initial load and a poll that returns new messages).\n- Keep paging with the returned `oldest_mo_ts` / `oldest_mt_ts` until `has_more` is `false` — the final page comes back with an empty `messages` array and both watermarks 0."
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"messages\": [\n    {\n      \"id\": \"669f0a1c2d3e4f5a6b7c8d90\",\n      \"message\": \"Earlier message\",\n      \"timestamp\": 1749500050,\n      \"type\": \"MO\"\n    }\n  ],\n  \"has_more\": true,\n  \"oldest_mo_ts\": 1749500050,\n  \"oldest_mt_ts\": 1749500000\n}"
            },
            {
              "name": "200 OK (No Older Messages)",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"messages\": [],\n  \"has_more\": false,\n  \"oldest_mo_ts\": 0,\n  \"oldest_mt_ts\": 0\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Email",
      "item": [
        {
          "name": "Send Email",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_dingo}}/email",
              "host": [
                "{{base_url_dingo}}"
              ],
              "path": [
                "email"
              ]
            },
            "description": "Send a transactional email. The sender must be on a registered, validated domain (see Email Domains).\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `SenderEmail` | string | Yes | From address. Must be on a registered, validated domain. |\n| `Subject` | string | Yes | Email subject. |\n| `Text` | string | Yes | Plain-text body. |\n| `Html` | string | No | HTML body. Defaults to `Text` if omitted. |\n| `SenderName` | string | No | Display name for the From address. |\n| `Recipient` | string or array | Conditional | To recipient(s). At least one of Recipient / CC / BCC is required; combined max 50. |\n| `CC` | string or array | Conditional | CC recipient(s). |\n| `BCC` | string or array | Conditional | BCC recipient(s). |\n| `ReplyTo` | string | No | Reply-To address. |\n| `Attachments` | array | No | Array of `{url, filename?}`. Requires the DINGO_ATTACHMENT account flag; max 5. |\n| `test` | boolean | No | Sandbox mode. When true, the request is fully validated (sender authorization, recipient limits, attachments) and a message record is created, but the email is **not** sent and **does not** consume email quota. Assessed as true unless the parameter is omitted or is one of these values: `false`, `\"false\"`, `0`, `\"0\"`. |\n\n**Test mode:** pass `test: true` to validate an email end-to-end without sending or billing. A `v2_emails` record is still created (visible via `GET /api/v5/email` with `Status: test`), but SES is never called.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `messages` | array | One entry per send. |\n| `messages[].Id` | string | Email id. |\n| `messages[].Status` | string | Email status. |\n| `messages[].Recipients` | object | `{To, CC, TotalCount}` — BCC omitted for privacy. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Email not enabled. Please contact us.` | 400 | Email is not enabled on this account. |\n| `Required parameter: {field} missing` | 400 | A required field (SenderEmail / Subject / Text) is missing. |\n| `Required parameter: At least one of Recipient, CC, or BCC must be provided` | 400 | No recipient supplied. |\n| `Too many recipients. Maximum 50 allowed, got {n}.` | 400 | Combined recipients exceed 50. |\n| `Invalid email addresses: {list}` | 400 | One or more recipient addresses are malformed. |\n| `Invalid Sender Email` | 400 | `SenderEmail` is malformed. |\n| `Invalid Sender Domain` | 400 | Sender domain is not registered or validated on this account. |\n| `Invalid Sender Domain or Mailbox` | 400 | For hosted-mailbox senders, the address is not one of the account's active mailboxes. |\n| `Attachments not enabled for this account` | 403 | Attachments require the DINGO_ATTACHMENT flag. |\n| `Maximum {n} attachments allowed` | 400 | Too many attachments (max 5). |\n| `Each attachment must have a url field` | 400 | An attachment entry is missing `url`. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"SenderEmail\": \"news@mail.example.com\",\n  \"SenderName\": \"Example\",\n  \"Subject\": \"Welcome\",\n  \"Text\": \"Hello there\",\n  \"Html\": \"<p>Hello there</p>\",\n  \"Recipient\": \"jane@example.com\",\n  \"ReplyTo\": \"support@example.com\"\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"messages\": [\n    {\n      \"Id\": \"683554c596937cc4b90f5cf7\",\n      \"Status\": \"queued\",\n      \"Recipients\": {\n        \"To\": [\n          \"jane@example.com\"\n        ],\n        \"CC\": [],\n        \"TotalCount\": 1\n      }\n    }\n  ]\n}"
            },
            {
              "name": "200 OK (test mode)",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"messages\": [\n    {\n      \"Id\": \"6650f1a2b3c4d5e6f7a8b9c0\",\n      \"Status\": \"test\",\n      \"Recipients\": {\n        \"To\": [\n          \"someone@example.com\"\n        ],\n        \"CC\": [],\n        \"TotalCount\": 1\n      }\n    }\n  ]\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Invalid Sender Domain\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "List Emails",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_dingo}}/email",
              "host": [
                "{{base_url_dingo}}"
              ],
              "path": [
                "email"
              ],
              "query": [
                {
                  "key": "after",
                  "value": "",
                  "description": "24-hex cursor — the `id` of the last email on the previous page.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "20",
                  "description": "Page size, 1–100. Default 20.",
                  "disabled": true
                }
              ]
            },
            "description": "List sent emails, newest first.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `emails` | array | Emails this page. |\n| `emails[].id` | string | Email id. |\n| `emails[].status` | string | Email status. |\n| `emails[].from` | string | From address. |\n| `emails[].sender_name` | string | From display name. |\n| `emails[].to` | array | To recipients. |\n| `emails[].cc` | array | CC recipients. |\n| `emails[].subject` | string | Subject. |\n| `emails[].created_at` | integer | Epoch seconds created. |\n| `emails[].method` | string | Send method. |\n| `count` | integer | Emails on this page. |\n| `next_page` | string | Relative path for the next page — present only when `count >= limit`. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid after parameter` | 400 | `after` is not a valid 24-hex cursor. |\n| `Invalid limit parameter` | 400 | `limit` is outside 1–100. |\n\n#### Notes\n- `next_page` appears only when a full page is returned (`count >= limit`); follow it until it is absent. It echoes any non-default `limit`. The paging examples below use `limit=2` to stay short.",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"emails\": [\n    {\n      \"id\": \"683554c596937cc4b90f5cf7\",\n      \"status\": \"sent\",\n      \"from\": \"news@mail.example.com\",\n      \"sender_name\": \"Example\",\n      \"to\": [\n        \"jane@example.com\"\n      ],\n      \"cc\": [],\n      \"subject\": \"Welcome\",\n      \"created_at\": 1717000000,\n      \"method\": \"api\"\n    },\n    {\n      \"id\": \"683554c596937cc4b90f5cf5\",\n      \"status\": \"sent\",\n      \"from\": \"news@mail.example.com\",\n      \"sender_name\": \"Example\",\n      \"to\": [\n        \"tom@example.com\"\n      ],\n      \"cc\": [],\n      \"subject\": \"Your receipt\",\n      \"created_at\": 1716999000,\n      \"method\": \"api\"\n    }\n  ],\n  \"count\": 2,\n  \"next_page\": \"/api/v5/email?after=683554c596937cc4b90f5cf5&limit=2\"\n}"
            },
            {
              "name": "200 OK (Last Page)",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"emails\": [\n    {\n      \"id\": \"683554c596937cc4b90f5cf1\",\n      \"status\": \"sent\",\n      \"from\": \"news@mail.example.com\",\n      \"sender_name\": \"Example\",\n      \"to\": [\n        \"amy@example.com\"\n      ],\n      \"cc\": [],\n      \"subject\": \"Order shipped\",\n      \"created_at\": 1716998000,\n      \"method\": \"api\"\n    }\n  ],\n  \"count\": 1\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Get Email",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_dingo}}/email/:id",
              "host": [
                "{{base_url_dingo}}"
              ],
              "path": [
                "email",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Email id."
                }
              ]
            },
            "description": "Fetch a single email, including its full text and HTML bodies.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `email` | object | id, status, from, sender_name, to, cc, subject, text, html, reply_to, created_at, method. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid email ID` | 400 | `id` is not a valid 24-hex id. |\n| `Email not found` | 400 | No such email, or not owned by this account. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"email\": {\n    \"id\": \"683554c596937cc4b90f5cf7\",\n    \"status\": \"sent\",\n    \"from\": \"news@mail.example.com\",\n    \"sender_name\": \"Example\",\n    \"to\": [\n      \"jane@example.com\"\n    ],\n    \"cc\": [],\n    \"subject\": \"Welcome\",\n    \"text\": \"Hello there\",\n    \"html\": \"<p>Hello there</p>\",\n    \"reply_to\": \"support@example.com\",\n    \"created_at\": 1717000000,\n    \"method\": \"api\"\n  }\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "List Inbound Emails",
          "request": {
            "method": "GET",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "url": {
              "raw": "{{base_url_dingo}}/inboundemail",
              "host": [ "{{base_url_dingo}}" ],
              "path": [ "inboundemail" ],
              "query": [
                { "key": "after", "value": "", "description": "24-hex cursor — the `id` of the last inbound email on the previous page.", "disabled": true },
                { "key": "limit", "value": "20", "description": "Page size, 1–1000. Default 20.", "disabled": true },
                { "key": "mailbox_address", "value": "", "description": "Optional. Restrict to inbound routed to this hosted mailbox address (lowercased). Omit for all inbound.", "disabled": true },
                { "key": "include_archived", "value": "1", "description": "Optional. Set to 1 to include archived inbound email. Archived email is excluded by default.", "disabled": true }
              ]
            },
            "description": "List received (inbound) emails for the account, newest first. Returns both hosted-mailbox-routed and custom-domain-routed inbound mail; pass `mailbox_address` to restrict to one hosted mailbox.\n\n#### Query parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `after` | string | No | 24-hex cursor; `id` of the last row on the previous page. |\n| `limit` | integer | No | Page size 1–1000, default 20. |\n| `mailbox_address` | string | No | Restrict to one hosted mailbox address. |\n| `include_archived` | boolean | No | Set to `1` to include archived inbound email. Excluded by default. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `emails` | array | Inbound emails this page, newest first. |\n| `emails[].id` | string | Inbound email id. |\n| `emails[].from` | string | Sender address. |\n| `emails[].from_name` | string | Sender display name, decoded to UTF-8. Empty when the sender supplied none, and on email received before this field shipped. |\n| `emails[].to` | string | Raw To header the mail was delivered to. |\n| `emails[].subject` | string | Subject. |\n| `emails[].has_attachments` | boolean | True if the email has any attachment (inline or file). |\n| `emails[].archived` | boolean | True when the account has archived this email. Only ever `true` when `include_archived` is set. |\n| `emails[].mailbox_address` | string | Present only for hosted-mailbox-routed inbound. |\n| `emails[].created_at` | integer | Epoch seconds received. |\n| `count` | integer | Emails on this page. |\n| `next_page` | string | Relative path for the next page — present only when `count >= limit`. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid after parameter` | 400 | `after` is not a valid 24-hex cursor. |\n| `Invalid limit parameter` | 400 | `limit` is non-numeric. |\n| `Invalid mailbox_address parameter` | 400 | `mailbox_address` is not a string. |\n| `Unsupported method` | 400 | The collection route was called with DELETE, or with POST (POST is only valid on `/inboundemail/{id}`). |\n\n#### Notes\n- `next_page` appears only when a full page is returned (`count >= limit`); follow it until it is absent. It echoes any non-default `limit`, the `mailbox_address` filter, and `include_archived`. The paging examples below use `limit=2` to stay short.\n- Archived inbound email is excluded from this list. Pass `include_archived=1` to include it; `next_page` echoes the flag. Archive with `POST /inboundemail/{id}`. Archiving cannot be reversed.",
            "body": {
              "mode": "raw",
              "options": { "raw": { "language": "json" } },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"emails\": [\n    {\n      \"id\": \"683554c596937cc4b90f5cf7\",\n      \"from\": \"jane@example.com\",\n      \"from_name\": \"Jane Smith\",\n      \"to\": \"support@mail.example.com\",\n      \"subject\": \"Re: Welcome\",\n      \"has_attachments\": false,\n      \"archived\": false,\n      \"created_at\": 1717000000\n    },\n    {\n      \"id\": \"683554c596937cc4b90f5cf5\",\n      \"from\": \"tom@example.com\",\n      \"from_name\": \"\",\n      \"to\": \"hello@mail.example.com\",\n      \"subject\": \"Invoice attached\",\n      \"has_attachments\": true,\n      \"archived\": false,\n      \"mailbox_address\": \"hello@mail.example.com\",\n      \"created_at\": 1716999000\n    }\n  ],\n  \"count\": 2,\n  \"next_page\": \"/api/v5/inboundemail?after=683554c596937cc4b90f5cf5&limit=2\"\n}"
            },
            {
              "name": "200 OK (Last Page)",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"emails\": [\n    {\n      \"id\": \"683554c596937cc4b90f5cf1\",\n      \"from\": \"amy@example.com\",\n      \"from_name\": \"Amy Jones\",\n      \"to\": \"support@mail.example.com\",\n      \"subject\": \"Question about my order\",\n      \"has_attachments\": false,\n      \"archived\": false,\n      \"created_at\": 1716998000\n    }\n  ],\n  \"count\": 1\n}"
            },
            {
              "name": "200 OK (Including Archived)",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"emails\": [\n    {\n      \"id\": \"683554c596937cc4b90f5cf7\",\n      \"from\": \"jane@example.com\",\n      \"from_name\": \"Jane Smith\",\n      \"to\": \"support@mail.example.com\",\n      \"subject\": \"Re: Welcome\",\n      \"has_attachments\": false,\n      \"archived\": false,\n      \"created_at\": 1717000000\n    },\n    {\n      \"id\": \"683554c596937cc4b90f5cf5\",\n      \"from\": \"tom@example.com\",\n      \"from_name\": \"\",\n      \"to\": \"hello@mail.example.com\",\n      \"subject\": \"Invoice attached\",\n      \"has_attachments\": true,\n      \"archived\": true,\n      \"mailbox_address\": \"hello@mail.example.com\",\n      \"created_at\": 1716999000\n    }\n  ],\n  \"count\": 2,\n  \"next_page\": \"/api/v5/inboundemail?after=683554c596937cc4b90f5cf5&include_archived=1&limit=2\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Get Inbound Email",
          "request": {
            "method": "GET",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "url": {
              "raw": "{{base_url_dingo}}/inboundemail/:id",
              "host": [ "{{base_url_dingo}}" ],
              "path": [ "inboundemail", ":id" ],
              "variable": [
                { "key": "id", "value": "", "description": "Inbound email id." }
              ]
            },
            "description": "Fetch a single received email, including its full text and HTML bodies and attachment metadata. Scoped to the owning account.\n\n#### Path parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `id` | string | Yes | 24-hex inbound email id. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `email.id` | string | Inbound email id. |\n| `email.from` | string | Sender address. |\n| `email.from_name` | string | Sender display name, decoded to UTF-8. Empty when the sender supplied none, and on email received before this field shipped. |\n| `email.to` | string | Raw To header. |\n| `email.subject` | string | Subject. |\n| `email.text` | string | Plain-text body. |\n| `email.html` | string | HTML body (inline `cid:` images already rewritten to S3 URLs). |\n| `email.attachments` | array | Attachment metadata. |\n| `email.attachments[].filename` | string | File name. |\n| `email.attachments[].content_type` | string | MIME type. |\n| `email.attachments[].size` | integer | Bytes. |\n| `email.attachments[].url` | string | Presigned S3 download URL, valid for 1 hour. |\n| `email.attachments[].content_id` | string | MIME Content-ID (inline images). |\n| `email.attachments[].is_inline` | boolean | True for embedded inline images. |\n| `email.mailbox_address` | string | Present only for hosted-mailbox-routed inbound. |\n| `email.mailbox_id` | string | Present only with `mailbox_address`. |\n| `email.archived` | boolean | True when the account has archived this email. Archived email stays fully readable through this endpoint. |\n| `email.archived_at` | integer | Epoch seconds of the archive request. Present only when `archived` is true. |\n| `email.created_at` | integer | Epoch seconds received. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid inbound email ID` | 400 | `id` is not a valid 24-hex id. |\n| `Inbound email not found` | 400 | No such inbound email, or not owned by this account. |\n| `Unsupported method` | 400 | The route was called with DELETE. POST on this route archives (see Archive Inbound Email). |",
            "body": {
              "mode": "raw",
              "options": { "raw": { "language": "json" } },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"email\": {\n    \"id\": \"683554c596937cc4b90f5cf7\",\n    \"from\": \"jane@example.com\",\n    \"from_name\": \"Jane Smith\",\n    \"to\": \"support@mail.example.com\",\n    \"subject\": \"Re: Welcome\",\n    \"text\": \"Thanks!\",\n    \"html\": \"<p>Thanks!</p>\",\n    \"attachments\": [],\n    \"archived\": false,\n    \"created_at\": 1717000000\n  }\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Archive Inbound Email",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "url": {
              "raw": "{{base_url_dingo}}/inboundemail/:id",
              "host": [ "{{base_url_dingo}}" ],
              "path": [ "inboundemail", ":id" ],
              "variable": [
                { "key": "id", "value": "", "description": "Inbound email id." }
              ]
            },
            "description": "Archive one received email. Archiving hides the email from `GET /inboundemail` unless that call passes `include_archived=1`; it never deletes the email or its attachments, does not change its one-year retention, and the email stays fully readable through `GET /inboundemail/{id}`.\n\n**Archiving is permanent.** There is no unarchive operation, on this endpoint or in the dashboard. Sending `archived: false` returns `Unarchiving is not supported`.\n\n#### Request body\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `key-id` | string | Yes | API key id (see intro auth). |\n| `key-secret` | string | Yes | API key secret (see intro auth). |\n| `archived` | boolean | Yes | Must be truthy (`true`, `1`, `\"true\"`). A falsy value is rejected - archiving cannot be reversed. |\n\n#### Path parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `id` | string | Yes | 24-hex inbound email id. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `message` | string | `Inbound email archived`. |\n| `id` | string | The inbound email id acted on. |\n| `archived` | boolean | Always `true` on success. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid inbound email ID` | 400 | `id` is not a valid 24-hex id. |\n| `archived Required. Please see our API Docs` | 400 | The body has no `archived` field. |\n| `Unarchiving is not supported` | 400 | `archived` was sent as `false`, `0`, `\"false\"`, or `null`. |\n| `Inbound email not found` | 400 | No such inbound email, or not owned by this account. |\n| `Unsupported method` | 400 | POSTed to `/inboundemail` with no id. |\n\n#### Notes\n- Idempotent: re-archiving an already-archived email succeeds and returns the same body. It refreshes `archived_at` to the time of the latest request.\n- Archiving is free and does not touch the email quota.",
            "body": {
              "mode": "raw",
              "options": { "raw": { "language": "json" } },
              "raw": "{\n  \"key-id\": \"{{key_id}}\",\n  \"key-secret\": \"{{key_secret}}\",\n  \"archived\": true\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"message\": \"Inbound email archived\",\n  \"id\": \"683554c596937cc4b90f5cf7\",\n  \"archived\": true\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Unarchiving is not supported\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Account",
      "item": [
        {
          "name": "Get Balance",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/balance",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "balance"
              ]
            },
            "description": "Get your account's credit balance and billing mode.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `balance` | object | Balance details. |\n| `balance.postpaid` | boolean | True if the account is postpaid. |\n| `balance.credits` | number | Available credits. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"balance\": {\n    \"postpaid\": false,\n    \"credits\": 1234.5\n  }\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Pre-warm Send Queue",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/prewarm",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "prewarm"
              ]
            },
            "description": "Pre-warm the send queue ahead of a large campaign. Requires the QUEUE_PREWARM account flag; usable once per 60 minutes.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `message` | string | Confirmation message. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Account does not have queue pre-warming enabled` | 400 | QUEUE_PREWARM flag not set on the account. |\n| `Queue was already pre-warmed recently. Please wait {n} minutes before trying again.` | 400 | Pre-warmed within the last 60 minutes. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"message\": \"Queue pre-warming initiated.\"\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Account does not have queue pre-warming enabled\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Logins",
      "item": [
        {
          "name": "Create Login",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/logins",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "logins"
              ]
            },
            "description": "Create (or re-invite) a sub-login on your account.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `name` | string | Yes | Login's display name. |\n| `email` | string | Yes | Login's email address. |\n| `role` | string | No | One of `admin`, `manager`, `sender`, `reporting`. Default `admin`. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `login_id` | string | The login's id. |\n| `is_new` | boolean | True if a new login was created. |\n| `message` | string | Confirmation message. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Missing required field: name` | 400 | `name` not supplied. |\n| `Missing required field: email` | 400 | `email` not supplied. |\n| `Invalid email address` | 400 | `email` is malformed. |\n| `Invalid role. Must be one of: admin, manager, sender, reporting` | 400 | `role` is not an allowed value. |\n| `Login already exists on this account` | 400 | A login with that email already exists here. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"name\": \"Jane Smith\",\n  \"email\": \"jane@example.com\",\n  \"role\": \"admin\"\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"login_id\": \"683554c596937cc4b90f5cf7\",\n  \"is_new\": true,\n  \"message\": \"Login created\"\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Invalid role. Must be one of: admin, manager, sender, reporting\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "List Logins",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/logins",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "logins"
              ]
            },
            "description": "List all logins on your account.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `logins` | array | Logins on the account. |\n| `logins[].login_id` | string | Login id. |\n| `logins[].name` | string | Display name. |\n| `logins[].email` | string | Email address. |\n| `logins[].role` | string | Role. |\n| `count` | integer | Number of logins. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"logins\": [\n    {\n      \"login_id\": \"683554c596937cc4b90f5cf7\",\n      \"name\": \"Jane Smith\",\n      \"email\": \"jane@example.com\",\n      \"role\": \"admin\"\n    }\n  ],\n  \"count\": 1\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Change Login Role",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/logins/:login_id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "logins",
                ":login_id"
              ],
              "variable": [
                {
                  "key": "login_id",
                  "value": "",
                  "description": "Login id."
                }
              ]
            },
            "description": "Change a login's role.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `action` | string | Yes | Must be `change_role`. |\n| `role` | string | Yes | One of `admin`, `manager`, `sender`, `reporting`. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `login_id` | string | The login's id. |\n| `role` | string | The new role. |\n| `message` | string | Confirmation message. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid login_id format` | 400 | `login_id` is not a valid id. |\n| `Missing required field: role` | 400 | `role` not supplied. |\n| `Invalid role. Must be one of: admin, manager, sender, reporting` | 400 | `role` is not an allowed value. |\n| `Login not found on this account` | 400 | No such login on this account. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"action\": \"change_role\",\n  \"role\": \"manager\"\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"login_id\": \"683554c596937cc4b90f5cf7\",\n  \"role\": \"manager\",\n  \"message\": \"Role updated\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Delete Login",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/logins/:login_id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "logins",
                ":login_id"
              ],
              "variable": [
                {
                  "key": "login_id",
                  "value": "",
                  "description": "Login id."
                }
              ]
            },
            "description": "Remove a login from your account.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `login_id` | string | The removed login's id. |\n| `message` | string | Confirmation message. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid login_id format` | 400 | `login_id` is not a valid id. |\n| `Login not found on this account` | 400 | No such login on this account. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"login_id\": \"683554c596937cc4b90f5cf7\",\n  \"message\": \"Login removed from account\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Campaigns",
      "item": [
        {
          "name": "Create campaign",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/campaigns",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "campaigns"
              ]
            },
            "description": "Create an SMS, email, or combined campaign. A campaign is created in `DRAFT` status. In a single call you can also set the campaign's content, add recipients inline, and send or schedule it — or do each step separately with the other endpoints in this folder.\n\nCampaigns are an account resource on the 5c SMS host (`{{base_url_sms}}`) for both channels.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `type` | string | No | `sms`, `email`, or `both`. Default `sms`. |\n| `title` | string | No | Campaign title. |\n| `sms_sender_id` | string | No | SMS sender ID or virtual number (SMS / both). |\n| `sms_body` | string | No | SMS message body (SMS / both). |\n| `sms_optout_enabled` | boolean | No | Append an opt-out link to the SMS. |\n| `sms_unicode_enabled` | boolean | No | Send the SMS as unicode. Requires the `UTF16` account feature. |\n| `sender_email` | string | No | From address; must be at one of your validated sending domains (email / both). |\n| `sender_name` | string | No | From name (email / both). |\n| `subject` | string | No | Email subject line (email / both). |\n| `email_body` | string | No | Email HTML body (email / both). |\n| `email_text` | string | No | Email plain-text body (email / both). |\n| `numbers` | string or array | No | Phone numbers to add as individual recipients. Array, or a comma/newline-delimited string. Max 100 individual recipients per call (numbers + emails combined). |\n| `emails` | string or array | No | Email addresses to add as individual recipients. Same format and cap as `numbers`. |\n| `contact_list_ids` | string or array | No | Contact list ids to add as recipient sources. Each must be a 24-char hex id you own. |\n| `send` | boolean | No | If true, send the campaign immediately after it is built. |\n| `schedule` | integer or string | No | Unix timestamp or a `strtotime`-parseable string. Schedules the send for that time; supplying it implies `send`. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. Carries the send error if an inline `send`/`schedule` failed its gating (the campaign is still created). |\n| `campaign_id` | string | The new campaign's id. |\n| `status` | string | `DRAFT`, or `SENDING` / `SCHEDULED` if sent inline. |\n| `recipient_count` | integer | Recipients currently on the campaign. |\n| `recipients_added` | integer | Individual recipients added (present only when inline recipients were supplied). |\n| `recipient_errors` | array | Per-recipient errors for skipped individuals (present only when inline recipients were supplied). |\n| `send` | object | The send result (present only when `send`/`schedule` was requested): `error`, `campaign_id`, `status`, `message`. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid campaign type` | 400 | `type` is not `sms`, `email`, or `both`. |\n| `Unicode requires the UTF16 feature on your account` | 400 | `sms_unicode_enabled` set without the `UTF16` account feature. |\n\n> **Note — inline send is not atomic.** When you pass `send`/`schedule` and the send gating fails (see the **Send / schedule campaign** endpoint for those errors), the campaign persists as `DRAFT`, the top-level `error` carries the send failure, and `send` holds the detail. Fix the issue and call the Send endpoint — do not re-create.",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"type\": \"sms\",\n  \"title\": \"July promo\",\n  \"sms_sender_id\": \"EXAMPLE\",\n  \"sms_body\": \"Hello from Acme!\",\n  \"sms_optout_enabled\": true,\n  \"contact_list_ids\": [\"683554c596937cc4b90f5cf7\"],\n  \"send\": false\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"campaign_id\": \"665f1a2b3c4d5e6f7a8b9c0d\",\n  \"status\": \"DRAFT\",\n  \"recipient_count\": 240,\n  \"recipients_added\": 0,\n  \"recipient_errors\": []\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Invalid campaign type\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "List campaigns",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/campaigns",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "campaigns"
              ]
            },
            "description": "List your account's campaigns, most-recent-first. Returns up to the 200 most recent campaigns; older campaigns are purged 365 days after creation.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `campaigns` | array | Campaigns, newest first. |\n| `campaigns[].campaign_id` | string | Campaign id. |\n| `campaigns[].title` | string | Campaign title. |\n| `campaigns[].status` | string | `DRAFT`, `SCHEDULED`, `SENDING`, or `SENT`. |\n| `campaigns[].type` | array | Channels: any of `sms`, `email`. |\n| `campaigns[].recipient_count` | integer | Recipients on the campaign. |\n| `campaigns[].schedule` | integer | Scheduled send time (unix), or null. |\n| `count` | integer | Number of campaigns returned. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"campaigns\": [\n    {\n      \"campaign_id\": \"665f1a2b3c4d5e6f7a8b9c0d\",\n      \"title\": \"July promo\",\n      \"status\": \"SENT\",\n      \"type\": [\"sms\"],\n      \"recipient_count\": 240,\n      \"schedule\": null\n    }\n  ],\n  \"count\": 1\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Get campaign",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/campaigns/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "campaigns",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Campaign id (24-char hex)."
                }
              ]
            },
            "description": "Fetch one campaign: its settings, recipients, and combined SMS/email delivery stats.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `campaign_id` | string | Campaign id. |\n| `title` | string | Campaign title. |\n| `status` | string | `DRAFT`, `SCHEDULED`, `SENDING`, or `SENT`. |\n| `type` | array | Channels: any of `sms`, `email`. |\n| `recipient_count` | integer | Recipients on the campaign. |\n| `schedule` | integer | Scheduled send time (unix), or null. |\n| `sms` | object | SMS settings (present for `sms`/`both`): `sender_id`, `body`, `optout_enabled`, `unicode_enabled`. |\n| `email` | object | Email settings (present for `email`/`both`): `sender_email`, `sender_name`, `subject`, `has_body`. |\n| `recipients` | array | Recipient rows: `id`, `type` (`individual`/`contact_list`), and either `recipient_type`+`value` or `contact_list_id`+`contact_list_name`+`contact_list_count`, plus `created`. |\n| `stats` | object | Delivery stats: `type` (`sms`/`email`/`both`/`none`); `sms` and/or `email` count objects. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid campaign_id format` | 400 | The path id is not a 24-char hex id. |\n| `Campaign not found` | 400 | No such campaign on this account. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"campaign_id\": \"665f1a2b3c4d5e6f7a8b9c0d\",\n  \"title\": \"July promo\",\n  \"status\": \"SENT\",\n  \"type\": [\"sms\"],\n  \"recipient_count\": 240,\n  \"schedule\": null,\n  \"sms\": {\n    \"sender_id\": \"EXAMPLE\",\n    \"body\": \"Hello from Acme!\",\n    \"optout_enabled\": true,\n    \"unicode_enabled\": false\n  },\n  \"recipients\": [\n    {\n      \"id\": \"665f1a2b3c4d5e6f7a8b9c11\",\n      \"type\": \"contact_list\",\n      \"contact_list_id\": \"683554c596937cc4b90f5cf7\",\n      \"contact_list_name\": \"VIP\",\n      \"contact_list_count\": 240,\n      \"created\": 1721700000\n    }\n  ],\n  \"stats\": {\n    \"type\": \"sms\",\n    \"sms\": { \"total\": 240, \"queued\": 0, \"sent\": 40, \"delivered\": 195, \"failed\": 5 }\n  }\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Campaign not found\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Update campaign",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/campaigns/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "campaigns",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Campaign id (24-char hex)."
                }
              ]
            },
            "description": "Update a draft campaign's settings. Only campaigns in `DRAFT` status can be edited. Supply `action: update` plus any of the content fields; only the fields you send are changed.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `action` | string | Yes | Must be `update`. |\n| `type` | string | No | `sms`, `email`, or `both`. |\n| `title` | string | No | Campaign title. |\n| `sms_sender_id` | string | No | SMS sender ID or virtual number. |\n| `sms_body` | string | No | SMS message body. |\n| `sms_optout_enabled` | boolean | No | Append an opt-out link to the SMS. |\n| `sms_unicode_enabled` | boolean | No | Send as unicode. Requires the `UTF16` account feature. |\n| `sender_email` | string | No | From address; must be at one of your validated domains. |\n| `sender_name` | string | No | From name. |\n| `subject` | string | No | Email subject line. |\n| `email_body` | string | No | Email HTML body. |\n| `email_text` | string | No | Email plain-text body. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `campaign_id` | string | Campaign id. |\n| `message` | string | Confirmation message. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid campaign_id format` | 400 | The path id is not a 24-char hex id. |\n| `Campaign not found` | 400 | No such campaign on this account. |\n| `Invalid or missing action` | 400 | `action` is absent or not a supported action. |\n| `Cannot edit campaign - not in draft status` | 400 | The campaign is not in `DRAFT`. |\n| `Invalid campaign type` | 400 | `type` is not `sms`, `email`, or `both`. |\n| `Unicode requires the UTF16 feature on your account` | 400 | `sms_unicode_enabled` set without the `UTF16` account feature. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"action\": \"update\",\n  \"title\": \"July promo (final)\",\n  \"sms_body\": \"Hello from Acme! Reply STOP to opt out.\"\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"campaign_id\": \"665f1a2b3c4d5e6f7a8b9c0d\",\n  \"message\": \"Campaign updated\"\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Cannot edit campaign - not in draft status\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Add recipients",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/campaigns/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "campaigns",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Campaign id (24-char hex)."
                }
              ]
            },
            "description": "Add recipients to a draft campaign — individual numbers, individual emails, and/or whole contact lists. Only campaigns in `DRAFT` status accept recipients. Individual numbers and emails are capped at 100 combined per call; contact lists have no per-call cap. Duplicates and invalid entries are skipped and reported in `errors` while the rest are added (the top-level `error` stays empty).\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `action` | string | Yes | Must be `add_recipients`. |\n| `numbers` | string or array | No | Phone numbers. Array, or comma/newline-delimited string. |\n| `emails` | string or array | No | Email addresses. Same format as `numbers`. |\n| `contact_list_ids` | string or array | No | Contact list ids (24-char hex) you own. |\n\nAt least one of `numbers`, `emails`, or `contact_list_ids` must be non-empty.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `added` | integer | Individual recipients successfully added. |\n| `errors` | array | Per-item messages for skipped entries — e.g. `Number already added: ...`, `Invalid email address: ...`, `Invalid contact list id: ...`, or `Maximum 100 individual recipients per call`. |\n| `recipient_count` | integer | Total recipients on the campaign after the call. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid campaign_id format` | 400 | The path id is not a 24-char hex id. |\n| `Campaign not found` | 400 | No such campaign on this account. |\n| `Invalid or missing action` | 400 | `action` is absent or not a supported action. |\n| `Cannot modify recipients - not in draft status` | 400 | The campaign is not in `DRAFT`. |\n| `No recipients provided` | 400 | None of `numbers`/`emails`/`contact_list_ids` supplied. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"action\": \"add_recipients\",\n  \"numbers\": [\"0404123123\", \"0404123124\"],\n  \"contact_list_ids\": [\"683554c596937cc4b90f5cf7\"]\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"added\": 2,\n  \"errors\": [],\n  \"recipient_count\": 242\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"No recipients provided\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Remove recipient",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/campaigns/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "campaigns",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Campaign id (24-char hex)."
                }
              ]
            },
            "description": "Remove a single recipient row (an individual, or a whole contact-list source) from a draft campaign. Use the recipient `id` from **Get campaign**'s `recipients` array. Only campaigns in `DRAFT` status can be modified.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `action` | string | Yes | Must be `remove_recipient`. |\n| `recipient_id` | string | Yes | The recipient row id (24-char hex). |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `recipient_count` | integer | Total recipients remaining. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid campaign_id format` | 400 | The path id is not a 24-char hex id. |\n| `Campaign not found` | 400 | No such campaign on this account. |\n| `Invalid or missing action` | 400 | `action` is absent or not a supported action. |\n| `Cannot modify recipients - not in draft status` | 400 | The campaign is not in `DRAFT`. |\n| `recipient_id is required` | 400 | `recipient_id` missing or not a valid id. |\n| `Recipient not found` | 400 | No such recipient row on this campaign. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"action\": \"remove_recipient\",\n  \"recipient_id\": \"665f1a2b3c4d5e6f7a8b9c11\"\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"recipient_count\": 2\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"recipient_id is required\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Clear recipients",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/campaigns/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "campaigns",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Campaign id (24-char hex)."
                }
              ]
            },
            "description": "Remove all recipients from a draft campaign. Only campaigns in `DRAFT` status can be modified.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `action` | string | Yes | Must be `clear_recipients`. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `recipient_count` | integer | Always `0` on success. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid campaign_id format` | 400 | The path id is not a 24-char hex id. |\n| `Campaign not found` | 400 | No such campaign on this account. |\n| `Invalid or missing action` | 400 | `action` is absent or not a supported action. |\n| `Cannot modify recipients - not in draft status` | 400 | The campaign is not in `DRAFT`. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"action\": \"clear_recipients\"\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"recipient_count\": 0\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Send / schedule campaign",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/campaigns/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "campaigns",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Campaign id (24-char hex)."
                }
              ]
            },
            "description": "Send a draft campaign now, or schedule it for a future time. The campaign must be in `DRAFT` and pass all readiness and account-gating checks. Omit `schedule` to send immediately; supply it to schedule.\n\nSend-time gating enforces, per channel: an active email plan and a verified sending domain (email), and SMS credits or a postpaid account (SMS). A coupon may only be attached to a Unified Virtual Number sender.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `action` | string | Yes | Must be `send`. |\n| `schedule` | integer or string | No | Unix timestamp or a `strtotime`-parseable string, in the future. Omit to send immediately. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `campaign_id` | string | Campaign id. |\n| `status` | string | `SENDING` (immediate) or `SCHEDULED`. |\n| `message` | string | Confirmation message. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid campaign_id format` | 400 | The path id is not a 24-char hex id. |\n| `Campaign not found` | 400 | No such campaign on this account. |\n| `Invalid or missing action` | 400 | `action` is absent or not a supported action. |\n| `Campaign is not in draft status` | 400 | The campaign is not in `DRAFT`. |\n| `You need an active email plan to send email campaigns` | 400 | Email campaign with no email quota. |\n| `You need a verified domain to send email campaigns` | 400 | Email campaign with no verified sending domain. |\n| `You need SMS credits or a postpaid account to send SMS campaigns` | 400 | SMS campaign with zero balance and not postpaid. |\n| `A coupon can only be attached when the Sender ID is a Unified Virtual Number. Remove the coupon or choose a unified sender.` | 400 | Coupon attached with a non-Blue sender. |\n| `Scheduled time must be in the future` | 400 | `schedule` did not parse or is not in the future. |\n| `No recipients added` | 400 | Readiness: campaign has no recipients. |\n| `SMS sender ID is required` | 400 | Readiness: SMS channel missing sender ID. |\n| `SMS message body is required` | 400 | Readiness: SMS channel missing body. |\n| `SMS message is too long (max 760 characters)` | 400 | Readiness: SMS body exceeds the GSM length limit. |\n| `Unicode SMS message is too long (max 335 characters)` | 400 | Readiness: unicode SMS body exceeds the unicode length limit. |\n| `Sender email is required` | 400 | Readiness: email channel missing sender email. |\n| `Sender name is required` | 400 | Readiness: email channel missing sender name. |\n| `Subject line is required` | 400 | Readiness: email channel missing subject. |\n| `Email body is required` | 400 | Readiness: email channel missing body. |\n| `Campaign is already sending` | 400 | Send already in progress. |\n| `Campaign is already scheduled` | 400 | A schedule is already set. |\n| `Campaign has already been sent` | 400 | The campaign was already sent. |\n| `Failed to start campaign` | 400 | The send could not be started (defensive fallback). |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"action\": \"send\"\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"campaign_id\": \"665f1a2b3c4d5e6f7a8b9c0d\",\n  \"status\": \"SENDING\",\n  \"message\": \"Campaign started\"\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"You need a verified domain to send email campaigns\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Cancel schedule",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/campaigns/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "campaigns",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Campaign id (24-char hex)."
                }
              ]
            },
            "description": "Cancel a scheduled campaign and return it to `DRAFT`. Only works while the campaign is `SCHEDULED` and more than 30 minutes remain before the scheduled send.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `action` | string | Yes | Must be `cancel_schedule`. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `campaign_id` | string | Campaign id. |\n| `status` | string | `DRAFT`. |\n| `message` | string | Confirmation message. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid campaign_id format` | 400 | The path id is not a 24-char hex id. |\n| `Campaign not found` | 400 | No such campaign on this account. |\n| `Invalid or missing action` | 400 | `action` is absent or not a supported action. |\n| `Campaign is not scheduled` | 400 | The campaign is not in `SCHEDULED`. |\n| `Cannot cancel - less than 30 minutes until scheduled send` | 400 | Too close to the scheduled send time. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"action\": \"cancel_schedule\"\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"campaign_id\": \"665f1a2b3c4d5e6f7a8b9c0d\",\n  \"status\": \"DRAFT\",\n  \"message\": \"Schedule cancelled\"\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Cannot cancel - less than 30 minutes until scheduled send\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Delete campaign",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/campaigns/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "campaigns",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Campaign id (24-char hex)."
                }
              ]
            },
            "description": "Delete a campaign and its recipients. Only draft campaigns can be deleted — campaigns that are sending, scheduled, or already sent cannot be removed.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `campaign_id` | string | The deleted campaign's id. |\n| `message` | string | Confirmation message. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid campaign_id format` | 400 | The path id is not a 24-char hex id. |\n| `Campaign not found` | 400 | No such campaign on this account. |\n| `Cannot delete campaign` | 400 | The campaign is sending, scheduled, or sent. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"campaign_id\": \"665f1a2b3c4d5e6f7a8b9c0d\",\n  \"message\": \"Campaign deleted\"\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Cannot delete campaign\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Sender IDs",
      "item": [
        {
          "name": "List Sender IDs",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/senderid",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "senderid"
              ]
            },
            "description": "List the sender IDs registered on your account, plus any a linked master account has chosen to share with you.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `senderids` | array | Registered sender IDs, and any shared with this account by a linked master account. |\n| `senderids[].id` | string | Sender ID record id. |\n| `senderids[].senderid` | string | The sender ID value. |\n| `senderids[].status` | string | Approval status: `pending`, `acma_pending`, `approved`, `acma_approved`, `disallowed`, or `unverified`. |\n| `senderids[].shared` | boolean | `true` when this Sender ID belongs to a linked master account and was shared with you. Shared Sender IDs can be used to send but cannot be edited or deleted through this account's API key. |\n| `senderids[].acma_details_id` | string | Id of the linked ACMA contact-details record. Pass it as `acma_details_id` on **Create Sender ID** to reuse the same details. Omitted when none is linked. |\n| `senderids[].acma_additional_details` | string | Free-text notes supplied for ACMA registration. Omitted when empty. |\n| `senderids[].acma_evidence` | object | Stored supporting evidence: `filename`, `content_type`, `size` (bytes) and `uploaded_at` (Unix timestamp). Omitted until the file has been stored, so it is also how you confirm an `acma_evidence_url` download completed. |\n\nThe three `acma_*` fields describe an ACMA registration, which belongs to the account that owns the sender ID — they are omitted entirely on rows where `shared` is `true`.",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"senderids\": [\n    {\n      \"id\": \"683554c596937cc4b90f5cf7\",\n      \"senderid\": \"EXAMPLE\",\n      \"status\": \"approved\",\n      \"shared\": false\n    },\n    {\n      \"id\": \"683554c596937cc4b90f5cf8\",\n      \"senderid\": \"MASTERBRAND\",\n      \"status\": \"acma_approved\",\n      \"shared\": true\n    },\n    {\n      \"id\": \"68a1f0c596937cc4b90f5d1a\",\n      \"senderid\": \"ACMEPTY\",\n      \"status\": \"acma_pending\",\n      \"shared\": false,\n      \"acma_details_id\": \"68a1f0c596937cc4b90f5d02\",\n      \"acma_additional_details\": \"ACMEPTY is our registered trading name.\",\n      \"acma_evidence\": {\n        \"filename\": \"authorisation-letter.pdf\",\n        \"content_type\": \"application/pdf\",\n        \"size\": 184320,\n        \"uploaded_at\": 1755043200\n      }\n    }\n  ]\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Create Sender ID",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/senderid",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "senderid"
              ]
            },
            "description": "Register a new sender ID for approval.\n\nText sender IDs must be registered with ACMA before they can send, so the registration material can be supplied with this call. Send the authorised contact details either as `acma_details` (the details themselves — we create the record and return its id) or as `acma_details_id` (an id from **Create ACMA Contact Details**, **List ACMA Contact Details**, or an earlier call to this endpoint) — one or the other, not both. `acma_additional_details` carries supporting information for the registration, and `acma_evidence_url` points at a supporting-evidence file — an authorisation letter, a trade-mark certificate, or whatever backs your claim to the sender ID — that we download and store against it.\n\nEvery ACMA and evidence field applies to text sender IDs only, and all are rejected when the sender ID already exists on the account — use the dashboard to change an existing one.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `senderid` | string | Yes | The sender ID to register. Letters and digits only; max 11 characters. |\n| `acma_details` | object | No | Authorised contact details to create and link. Same fields as **Create ACMA Contact Details**: `contact_name`, `contact_email` and `business_name` are required within the object, `contact_phone`, `abn`, `business_web`, `business_address`, `business_phone` optional. Text sender IDs only. Cannot be combined with `acma_details_id`. |\n| `acma_details_id` | string | No | Id of an ACMA contact-details set already on this account, to link instead of creating one. Text sender IDs only. Cannot be combined with `acma_details`. |\n| `acma_additional_details` | string | No | Supporting information for the ACMA registration. Max 2000 characters. Text sender IDs only. |\n| `acma_evidence_url` | string | No | Public `http`/`https` URL of your supporting evidence (authorisation letter, trade-mark certificate, registration document). We check the URL's shape while handling the request and download it shortly afterwards in the background: 10-second timeout, up to 3 redirects, max 2 MB, must be a PDF, JPG, PNG, DOC or DOCX. Text sender IDs only. |\n| `acma_evidence_filename` | string | No | Filename to store the evidence under. Defaults to the last path segment of `acma_evidence_url`. Its extension decides whether the file type is accepted. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `message` | string | Confirmation message. |\n| `id` | string | Sender ID record id. Returned for text sender IDs. |\n| `acma_details_id` | string | Id of the contact-details set created or linked. Reuse it on your next sender ID. Present only when `acma_details` or `acma_details_id` was supplied. |\n\n#### Notes\n- Registration is not immediate: a new text sender ID is created `pending` and cannot send until it is reviewed, approved and registered with ACMA. This may take several business days. Poll **List Sender IDs** for the status.\n- Supplying `acma_details`, `acma_additional_details` or `acma_evidence_url` notifies our support team so the registration can be progressed.\n- Contact-details sets are reusable across sender IDs. Pass `acma_details` once, then reuse the returned `acma_details_id`, rather than sending the same details again.\n- Nothing is written until every field validates, so a rejected request leaves no sender ID and no contact-details record.\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Missing Sender ID` | 400 | `senderid` not supplied, or not a string. |\n| `Invalid new Sender ID` | 400 | `senderid` is not 1-11 letters and digits. |\n| `ACMA registration details are only supported for text Sender IDs` | 400 | `acma_details`, `acma_details_id`, `acma_additional_details` or `acma_evidence_url` supplied with a numeric sender ID. |\n| `Sender ID already exists on this account` | 400 | Registration material supplied for a sender ID already on the account. |\n| `Supply either acma_details or acma_details_id, not both` | 400 | Both were supplied. |\n| `Invalid ACMA contact details` | 400 | `acma_details` is not an object, or one of its fields is not a string. |\n| `Contact Name, Contact Email and Business Name are required.` | 400 | `acma_details` is missing one of the three required fields. |\n| `Invalid ACMA details ID` | 400 | `acma_details_id` is not a 24-character hexadecimal id. |\n| `ACMA details not found` | 400 | `acma_details_id` does not belong to this account. |\n| `Invalid Additional Details` | 400 | `acma_additional_details` is not a string. |\n| `Additional Details is too long. Maximum 2000 characters.` | 400 | `acma_additional_details` exceeds 2000 characters. |\n| `Invalid supporting evidence URL` | 400 | `acma_evidence_url` is not a string. |\n| `Supporting evidence URL is not a valid URL.` | 400 | `acma_evidence_url` is malformed. |\n| `Supporting evidence URL must be an http or https URL.` | 400 | `acma_evidence_url` uses another scheme, or has no host. |\n| `Supporting evidence must be a PDF, JPG, PNG, DOC or DOCX file.` | 400 | The filename extension is not an accepted type. |\n| `Sender ID not found.` | 400 | The sender ID was removed while this request was in flight. |\n| `Unable to queue the supporting evidence` | 400 | The sender ID and its details were saved, but the evidence download could not be scheduled. Upload the file in the dashboard; do not retry the create. |\n| `Unable to notify support for this Sender ID` | 400 | The sender ID and its details were saved, but the support notification could not be queued. Do not retry the create; contact support. |\n\nDownload problems — an unreachable URL, a file over 2 MB, a link that has expired — are **not** returned here, because the download happens after this response. We retry once and then email your account contact.\n",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"senderid\": \"EXAMPLE\",\n  \"acma_details\": {\n    \"contact_name\": \"Jane Citizen\",\n    \"contact_email\": \"jane@example.com\",\n    \"contact_phone\": \"0400000000\",\n    \"abn\": \"12345678901\",\n    \"business_name\": \"Example Pty Ltd\",\n    \"business_web\": \"https://www.example.com\",\n    \"business_address\": \"1 Example Street, Sydney NSW 2000\",\n    \"business_phone\": \"0290000000\"\n  },\n  \"acma_additional_details\": \"EXAMPLE is our registered trading name.\",\n  \"acma_evidence_url\": \"https://files.example.com/authorisation-letter.pdf\"\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"message\": \"Sender ID created\",\n  \"id\": \"683554c596937cc4b90f5cf7\",\n  \"acma_details_id\": \"68a1f0c596937cc4b90f5d02\"\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Supporting evidence must be a PDF, JPG, PNG, DOC or DOCX file.\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Delete Sender ID",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/senderid/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "senderid",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Sender ID record id."
                }
              ]
            },
            "description": "Remove a sender ID from your account.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid Sender ID format` | 400 | The `id` path segment is not a 24-character hexadecimal id. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Create ACMA Contact Details",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/acmadetails",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "acmadetails"
              ]
            },
            "description": "Create a set of ACMA authorised contact details on your account. ACMA requires these details for every text sender ID; the `id` returned here is what **Create Sender ID** takes as `acma_details_id`, and what **List Sender IDs** reports as `senderids[].acma_details_id`.\n\nSets are per-account and reusable — create one and link it to as many sender IDs as you like. **Create Sender ID** can also create a set inline from raw `acma_details`, which is the one-call alternative to this endpoint. Changing and deleting sets is done in the dashboard under Settings > Sender IDs.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `contact_name` | string | Yes | Name of the authorised representative. |\n| `contact_email` | string | Yes | Email of the authorised representative. ACMA may email this address to confirm the registration. Stored lowercased. |\n| `business_name` | string | Yes | Registered business or organisation name. |\n| `contact_phone` | string | No | Phone number of the authorised representative. |\n| `abn` | string | No | ABN of the entity. Omit for non-ABN entities such as sole traders or individuals. |\n| `business_web` | string | No | Business website. |\n| `business_address` | string | No | Registered business address. |\n| `business_phone` | string | No | Business phone number. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `message` | string | Confirmation message. |\n| `id` | string | Contact-details record id. Pass this as `acma_details_id` on **Create Sender ID**. |\n\n#### Notes\n- Duplicate sets are allowed: each call creates a new record.\n- A set cannot be changed or removed once a sender ID linked to it has been submitted to or registered with ACMA.\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Contact Name, Contact Email and Business Name are required.` | 400 | One of the three required fields is missing or empty. |\n| `Invalid ACMA contact details` | 400 | A supplied field is not a string. |\n| `Unable to notify support for these contact details` | 400 | The details were saved, but the support notification could not be queued. Do not retry; contact support — find the set's id with **List ACMA Contact Details**. |\n| `Unsupported method. Please see our API Docs` | 400 | `DELETE` on this path. Contact-details sets are changed and removed in the dashboard, not over the API. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"contact_name\": \"Jane Citizen\",\n  \"contact_email\": \"jane@example.com\",\n  \"contact_phone\": \"0400000000\",\n  \"abn\": \"12345678901\",\n  \"business_name\": \"Example Pty Ltd\",\n  \"business_web\": \"https://www.example.com\",\n  \"business_address\": \"1 Example Street, Sydney NSW 2000\",\n  \"business_phone\": \"0290000000\"\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"message\": \"ACMA contact details created\",\n  \"id\": \"68a1f0c596937cc4b90f5d02\"\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Contact Name, Contact Email and Business Name are required.\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "List ACMA Contact Details",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/acmadetails",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "acmadetails"
              ]
            },
            "description": "List the ACMA authorised contact-details sets on your account, oldest first. Use it to recover an `acma_details_id` you did not keep, or to check which details a sender ID is registered against.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `count` | integer | Number of sets returned. |\n| `acma_details` | array | The account's contact-details sets. |\n| `acma_details[].id` | string | Record id. Pass as `acma_details_id` on **Create Sender ID**. |\n| `acma_details[].contact_name` | string | Authorised representative's name. |\n| `acma_details[].contact_email` | string | Authorised representative's email, lowercased. |\n| `acma_details[].contact_phone` | string | Authorised representative's phone. Empty when not supplied. |\n| `acma_details[].abn` | string | ABN. Empty for non-ABN entities. |\n| `acma_details[].business_name` | string | Registered business or organisation name. |\n| `acma_details[].business_web` | string | Business website. Empty when not supplied. |\n| `acma_details[].business_address` | string | Registered business address. Empty when not supplied. |\n| `acma_details[].business_phone` | string | Business phone. Empty when not supplied. |\n| `acma_details[].created` | integer | Unix timestamp (seconds) the set was created. `null` on sets that predate this field. |\n\n#### Notes\n- An account with no sets returns `count: 0` and an empty array, not an error.\n- To see which sender ID uses which set, read `senderids[].acma_details_id` from **List Sender IDs**.\n\n#### Errors\nNone beyond authentication.",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"count\": 1,\n  \"acma_details\": [\n    {\n      \"id\": \"68a1f0c596937cc4b90f5d02\",\n      \"contact_name\": \"Jane Citizen\",\n      \"contact_email\": \"jane@example.com\",\n      \"contact_phone\": \"0400000000\",\n      \"abn\": \"12345678901\",\n      \"business_name\": \"Example Pty Ltd\",\n      \"business_web\": \"https://www.example.com\",\n      \"business_address\": \"1 Example Street, Sydney NSW 2000\",\n      \"business_phone\": \"0290000000\",\n      \"created\": 1755043200\n    }\n  ]\n}"
            },
            {
              "name": "200 OK (no sets)",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"count\": 0,\n  \"acma_details\": []\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Virtual Numbers",
      "item": [
        {
          "name": "List Virtual Numbers",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/virtualnumber",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "virtualnumber"
              ]
            },
            "description": "List the virtual numbers on your account.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `virtualnumbers` | array | Virtual numbers. |\n| `virtualnumbers[].id` | string | Virtual number record id. |\n| `virtualnumbers[].number` | string | Number in international format. |\n| `virtualnumbers[].number_formatted` | string | Human-formatted number. |\n| `virtualnumbers[].country` | string | Country code. |\n| `virtualnumbers[].type` | string | `standard` or `unified`. |\n| `count` | integer | Number of virtual numbers. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"virtualnumbers\": [\n    {\n      \"id\": \"683554c596937cc4b90f5cf7\",\n      \"number\": \"61400000000\",\n      \"number_formatted\": \"0400 000 000\",\n      \"country\": \"AU\",\n      \"type\": \"standard\"\n    }\n  ],\n  \"count\": 1\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Purchase Virtual Number",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/virtualnumber",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "virtualnumber"
              ]
            },
            "description": "Purchase a virtual number. Charges the card on file and creates a monthly subscription. Default limit 2 numbers unless the MORE_VMNS flag is set.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `country` | string | Yes | Only `AU` is supported for API purchases. |\n| `type` | string | No | `standard` or `unified`. Default `standard`; `unified` requires Unified Messaging to be enabled for the account and provisions a Unified Virtual Number, which `GET /virtualnumber` reports as `type: unified`. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `message` | string | Confirmation message. |\n| `virtualnumber` | object | `{id, number, number_formatted, country}`. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Missing required parameter: country` | 400 | `country` not supplied. |\n| `Invalid country. Currently only AU is supported for API requests.` | 400 | `country` is not `AU`. |\n| `Invalid type. Must be \"standard\" or \"unified\".` | 400 | `type` is not an allowed value. |\n| `Your account is not enabled for Unified Mobile Numbers. Please contact us.` | 400 | `type: unified` without the ENABLE_UNIFIED flag. |\n| `Your account is currently on hold. Please contact us to purchase a virtual number.` | 400 | Account is on hold. |\n| `Maximum virtual numbers reached. Contact us to request increaed quota.` | 400 | Number limit reached (default 2). |\n| `No payment method on file. Please add a payment method in the dashboard.` | 400 | No card on file. |\n| `Invalid subscription plan` | 400 | Subscription plan could not be resolved. |\n| `Your payment was declined by your bank.` | 400 | Card charge declined. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"country\": \"AU\",\n  \"type\": \"standard\"\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"message\": \"Virtual number purchased\",\n  \"virtualnumber\": {\n    \"id\": \"683554c596937cc4b90f5cf7\",\n    \"number\": \"61400000000\",\n    \"number_formatted\": \"0400 000 000\",\n    \"country\": \"AU\"\n  }\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Invalid country. Currently only AU is supported for API requests.\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Delete Virtual Number",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/virtualnumber/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "virtualnumber",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Virtual number record id."
                }
              ]
            },
            "description": "Release a virtual number and cancel its subscription.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `message` | string | Confirmation message. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid virtual number ID format` | 400 | `id` is not a valid id. |\n| `Virtual number not found` | 400 | No such virtual number. |\n| `Unauthorized - you do not own this virtual number` | 400 | Number not owned by this account. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"message\": \"Virtual number released\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Email Domains",
      "item": [
        {
          "name": "List Domains",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_dingo}}/domain",
              "host": [
                "{{base_url_dingo}}"
              ],
              "path": [
                "domain"
              ]
            },
            "description": "List the email domains registered on your account.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `domains` | array | Registered domains. |\n| `domains[].id` | string | Domain record id. |\n| `domains[].domain` | string | Domain name. |\n| `domains[].subdomain` | string | Sending subdomain. |\n| `domains[].status` | string | Verification status. |\n| `domains[].dkim_names` | array | DKIM record names. |\n| `domains[].verification` | string | SES verification state. |\n| `count` | integer | Number of domains. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"domains\": [\n    {\n      \"id\": \"683554c596937cc4b90f5cf7\",\n      \"domain\": \"example.com\",\n      \"subdomain\": \"email\",\n      \"status\": \"verified\",\n      \"dkim_names\": [\n        \"k1._domainkey\"\n      ],\n      \"verification\": \"verified\"\n    }\n  ],\n  \"count\": 1\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Get Domain",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_dingo}}/domain/:id",
              "host": [
                "{{base_url_dingo}}"
              ],
              "path": [
                "domain",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Domain record id."
                }
              ]
            },
            "description": "Fetch a single email domain, including its DKIM and verification details.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `domain` | object | id, domain, subdomain, status, dkim_names, verification. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Failed (Invalid Domain ID format)` | 400 | The `id` path segment is not a 24-character hexadecimal id. |\n| `Failed (Domain not found or unauthorized)` | 400 | No such domain, or not owned by this account. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"domain\": {\n    \"id\": \"683554c596937cc4b90f5cf7\",\n    \"domain\": \"example.com\",\n    \"subdomain\": \"email\",\n    \"status\": \"verified\",\n    \"dkim_names\": [\n      \"k1._domainkey\"\n    ],\n    \"verification\": \"verified\"\n  }\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Create Domain",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_dingo}}/domain",
              "host": [
                "{{base_url_dingo}}"
              ],
              "path": [
                "domain"
              ]
            },
            "description": "Register a new email domain. Email must be enabled and your plan's domain limit must not be exceeded.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `domain` | string | Yes | Domain name (valid domain format). |\n| `subdomain` | string | No | Sending subdomain; letters, numbers, hyphens. Default `email`. If a full host is supplied it is auto-corrected and a `warning` is returned. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `message` | object | `{id, domain}`. |\n| `warning` | string | Present only when the subdomain was auto-corrected. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Email not enabled. Please contact us.` | 400 | Email is not enabled on this account. |\n| `Domain limit reached. Your plan allows {n} domain{s}. Please upgrade your plan or contact us.` | 400 | Plan domain limit reached. |\n| `Missing Domain` | 400 | `domain` not supplied. |\n| `Invalid Domain` | 400 | `domain` is not a valid domain. |\n| `Domain already registered. Please contact us.` | 400 | Domain already exists. |\n| `Invalid subdomain. Use only letters, numbers, and hyphens.` | 400 | `subdomain` contains invalid characters. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"domain\": \"example.com\",\n  \"subdomain\": \"email\"\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"message\": {\n    \"id\": \"683554c596937cc4b90f5cf7\",\n    \"domain\": \"example.com\"\n  }\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Invalid Domain\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Mailboxes",
      "description": "Hosted mailboxes on the shared mailbox domain — send-and-receive addresses that need no domain of your own. Your plan's mailbox quota caps how many active mailboxes the account may have. Mailboxes are never deleted via the API: `DELETE` returns `Unsupported method. Please see our API Docs` (HTTP 400). Disable a mailbox instead; mailboxes are removed only when the account closes.",
      "item": [
        {
          "name": "List Mailboxes",
          "request": {
            "method": "GET",
            "header": [ { "key": "Content-Type", "value": "application/json" } ],
            "url": {
              "raw": "{{base_url_dingo}}/mailboxes",
              "host": [ "{{base_url_dingo}}" ],
              "path": [ "mailboxes" ]
            },
            "description": "List the hosted mailboxes on your account, active and inactive.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `mailboxes` | array | One object per mailbox. |\n| `mailboxes[].id` | string | Mailbox id (use with Enable / Disable Mailbox). |\n| `mailboxes[].address` | string | Full mailbox address. |\n| `mailboxes[].active` | boolean | `false` when the mailbox is disabled — inbound to it is dropped and it cannot send. |\n| `mailboxes[].created` | integer | Unix timestamp the mailbox was created, or `null`. |\n| `count` | integer | Number of mailboxes returned. |\n| `error` | string | Empty on success. |\n\n#### Errors\nNo endpoint-specific errors — authentication errors per the intro's 401 table.",
            "body": {
              "mode": "raw",
              "options": { "raw": { "language": "json" } },
              "raw": "{}"
            }
          },
          "response": [
            { "name": "200 OK", "code": 200, "status": "OK", "body": "{\n  \"error\": \"\",\n  \"count\": 2,\n  \"mailboxes\": [\n    {\n      \"id\": \"66a1f2c3d4e5f6a7b8c9d0e1\",\n      \"address\": \"newsletter@mydingo.au\",\n      \"active\": true,\n      \"created\": 1753142400\n    },\n    {\n      \"id\": \"66a1f2c3d4e5f6a7b8c9d0e2\",\n      \"address\": \"old@mydingo.au\",\n      \"active\": false,\n      \"created\": 1750464000\n    }\n  ]\n}" },
            { "name": "401 Unauthorized", "code": 401, "status": "Unauthorized", "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}" }
          ]
        },
        {
          "name": "Create Mailbox",
          "request": {
            "method": "POST",
            "header": [ { "key": "Content-Type", "value": "application/json" } ],
            "url": {
              "raw": "{{base_url_dingo}}/mailboxes",
              "host": [ "{{base_url_dingo}}" ],
              "path": [ "mailboxes" ]
            },
            "description": "Create a hosted mailbox. The new mailbox is active immediately and can send and receive at `<name>@mydingo.au`. Creation counts against your plan's mailbox quota (active mailboxes only).\n\n#### Request body\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `name` | string | yes | The local part (the text before the `@`). Lowercased. Letters, numbers and `. _ -` only, must start and end with a letter or number, maximum 64 characters. `+` is not allowed. Reserved names (role addresses such as `postmaster`, `abuse`, `admin`, and brand terms) are rejected. Must be globally unique across all accounts. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `mailbox.id` | string | The new mailbox id. |\n| `mailbox.address` | string | The full mailbox address. |\n| `mailbox.active` | boolean | Always `true` on create. |\n| `mailbox.created` | integer | Unix timestamp. |\n| `message` | string | `Mailbox created`. |\n| `error` | string | Empty on success. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Mailboxes are not included in your plan` | 400 | The account's mailbox quota is 0. |\n| `Unable to create mailboxes at this time. Please contact us.` | 400 | Please contact us |\n| `Mailbox limit reached` | 400 | The account already has as many active mailboxes as its quota allows. |\n| `Name Required. Please see our API Docs` | 400 | `name` missing or empty. |\n| `Mailbox name may only contain letters, numbers, and . _ - characters.` | 400 | `name` fails the format rule. |\n| `Mailbox name must be 64 characters or fewer.` | 400 | `name` longer than 64 characters. |\n| `That mailbox name is reserved. Please choose another name.` | 400 | `name` is on the reserved list. |\n| `That mailbox is already taken. Please choose another name.` | 400 | The address exists on any account (including disabled mailboxes). |",
            "body": {
              "mode": "raw",
              "options": { "raw": { "language": "json" } },
              "raw": "{\n  \"name\": \"newsletter\"\n}"
            }
          },
          "response": [
            { "name": "200 OK", "code": 200, "status": "OK", "body": "{\n  \"error\": \"\",\n  \"message\": \"Mailbox created\",\n  \"mailbox\": {\n    \"id\": \"66a1f2c3d4e5f6a7b8c9d0e1\",\n    \"address\": \"newsletter@mydingo.au\",\n    \"active\": true,\n    \"created\": 1753142400\n  }\n}" },
            { "name": "400 Bad Request", "code": 400, "status": "Bad Request", "body": "{\n  \"error\": \"That mailbox is already taken. Please choose another name.\"\n}" },
            { "name": "401 Unauthorized", "code": 401, "status": "Unauthorized", "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}" }
          ]
        },
        {
          "name": "Enable / Disable Mailbox",
          "request": {
            "method": "POST",
            "header": [ { "key": "Content-Type", "value": "application/json" } ],
            "url": {
              "raw": "{{base_url_dingo}}/mailboxes/:id",
              "host": [ "{{base_url_dingo}}" ],
              "path": [ "mailboxes", ":id" ],
              "variable": [ { "key": "id", "value": "", "description": "Mailbox id (from List Mailboxes)." } ]
            },
            "description": "Enable or disable a hosted mailbox. A disabled mailbox drops inbound email, cannot be used as a sender address, and does not count toward the mailbox quota — but keeps its address reserved to your account. Re-enabling is blocked while the account is already at its active-mailbox quota. There is no delete: mailboxes are removed only when the account closes.\n\n#### Request body\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `active` | boolean | yes | `true` to enable, `false` to disable. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `mailbox` | object | The updated mailbox (`id`, `address`, `active`, `created`). |\n| `message` | string | `Mailbox updated`. |\n| `error` | string | Empty on success. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid Mailbox ID` | 400 | The path id is not a 24-character hex id. |\n| `Mailbox Not Found` | 400 | No mailbox with that id on this account. |\n| `active Required. Please see our API Docs` | 400 | `active` missing or not a boolean. |\n| `Mailbox limit reached` | 400 | Enabling would exceed the account's active-mailbox quota. |",
            "body": {
              "mode": "raw",
              "options": { "raw": { "language": "json" } },
              "raw": "{\n  \"active\": false\n}"
            }
          },
          "response": [
            { "name": "200 OK", "code": 200, "status": "OK", "body": "{\n  \"error\": \"\",\n  \"message\": \"Mailbox updated\",\n  \"mailbox\": {\n    \"id\": \"66a1f2c3d4e5f6a7b8c9d0e1\",\n    \"address\": \"newsletter@mydingo.au\",\n    \"active\": false,\n    \"created\": 1753142400\n  }\n}" },
            { "name": "401 Unauthorized", "code": 401, "status": "Unauthorized", "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}" }
          ]
        }
      ]
    },
    {
      "name": "Contacts",
      "item": [
        {
          "name": "Create Contact List",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/lists",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "lists"
              ]
            },
            "description": "Create a contact list.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `name` | string | Yes | List name. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `list.id` | string | New list id. |\n| `list.name` | string | List name. |\n| `list.status` | string | `active` on creation. |\n| `list.count` | integer | Contact count (0 for a new list). |\n| `message` | string | Confirmation message. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Missing required field: name` | 400 | `name` not supplied or empty. |\n| `List update is not supported` | 400 | POSTing to a list id (`/lists/{id}`) — renaming or changing a list's status is not available via the API; manage it in the dashboard. |\n\n#### Notes\n- Lists are create-and-delete only through the API. There is no rename or archive endpoint.\n- Deleting a list also deletes every contact in it (see Delete List).",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"name\": \"VIP Customers\"\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"list\": {\n    \"id\": \"683554c596937cc4b90f5cf7\",\n    \"name\": \"VIP Customers\",\n    \"status\": \"active\",\n    \"count\": 0\n  },\n  \"message\": \"List created\"\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Missing required field: name\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "List Contact Lists",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/lists",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "lists"
              ]
            },
            "description": "List all contact lists on your account, each with its current contact count.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `lists` | array | Contact lists. |\n| `lists[].id` | string | List id. |\n| `lists[].name` | string | List name. |\n| `lists[].status` | string | `active` or `archived`. |\n| `lists[].count` | integer | Number of contacts in the list. |\n| `count` | integer | Number of lists. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"lists\": [\n    {\n      \"id\": \"683554c596937cc4b90f5cf7\",\n      \"name\": \"VIP Customers\",\n      \"status\": \"active\",\n      \"count\": 128\n    }\n  ],\n  \"count\": 1\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Get Contact List",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/lists/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "lists",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Contact list id (24-hex)."
                }
              ]
            },
            "description": "Get a single contact list by id.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `list.id` | string | List id. |\n| `list.name` | string | List name. |\n| `list.status` | string | `active` or `archived`. |\n| `list.count` | integer | Number of contacts in the list. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid list ID format` | 400 | The id is not a 24-hex value. |\n| `List not found` | 400 | No such list on this account. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"list\": {\n    \"id\": \"683554c596937cc4b90f5cf7\",\n    \"name\": \"VIP Customers\",\n    \"status\": \"active\",\n    \"count\": 128\n  }\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"List not found\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Delete Contact List",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/lists/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "lists",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Contact list id (24-hex)."
                }
              ]
            },
            "description": "Delete a contact list **and every contact in it**. This cannot be undone.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `message` | string | Confirmation message. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid list ID format` | 400 | The id is not a 24-hex value. |\n| `List not found` | 400 | No such list on this account. |\n\n#### Notes\n- The delete cascades: every contact whose `list_id` is this list is removed along with the list.",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"message\": \"List and its contacts deleted\"\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"List not found\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Create Contact",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/contacts",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "contacts"
              ]
            },
            "description": "Create one contact, or many in a single call.\n\n- **Single:** send the contact fields at the top level.\n- **Batch:** send a `contacts` array. Every row is inserted into the one `list_id`, and the response reports per-row results. Batch is best-effort — a row that isn't a JSON object is skipped and reported in `results[]`; the rest still insert. Max 1000 rows per call.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `list_id` | string | Yes | Target list id; must belong to your account. |\n| `number` | string | No | Phone number; normalised to 614… format on save. |\n| `first_name` | string | No | Contact's first name. |\n| `last_name` | string | No | Contact's last name. |\n| `email` | string | No | Contact's email address. |\n| `meta` | object | No | Custom fields — arbitrary key/value pairs. Scalar values only (array/object values are dropped); `.` and `$` in keys are replaced with `_`. |\n| `contacts` | array | No | Batch mode: array of contact objects, each carrying the fields above except `list_id`. Presence of this field switches to batch mode. |\n\n#### Response fields (single)\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `contact` | object | The created contact: `id`, `list_id`, `number`, `first_name`, `last_name`, `email`, `meta`. |\n| `message` | string | Confirmation message. |\n\n#### Response fields (batch)\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty — a batch always returns HTTP 200; per-row failures are in `results`. |\n| `created` | integer | Rows inserted. |\n| `failed` | integer | Rows skipped. |\n| `results` | array | Per row: `{index, id}` on success or `{index, error}` on failure. |\n| `message` | string | `Batch processed`. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Missing required field: list_id` | 400 | `list_id` not supplied. |\n| `Invalid list ID format` | 400 | `list_id` not a 24-hex value. |\n| `List not found` | 400 | The list doesn't exist or isn't yours. |\n| `contacts must be a non-empty array` | 400 | Batch mode with an empty or non-array `contacts`. |\n| `Batch too large. Maximum 1000 contacts per request` | 400 | Batch `contacts` has more than 1000 rows. |\n| `Invalid contact object` | (per-row) | A `contacts[]` row is not an object — reported in `results[].error`, not at the top level (HTTP stays 200). |\n\n#### Notes\n- Custom fields have no per-account schema; any key you send under `meta` is stored as-is.\n- Create is not deduplicated — re-sending the same contact creates a duplicate.\n- A batch targets a single list; mixing lists in one call is not supported.",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"list_id\": \"683554c596937cc4b90f5cf7\",\n  \"number\": \"0412333555\",\n  \"first_name\": \"Jane\",\n  \"last_name\": \"Smith\",\n  \"email\": \"jane@example.com\",\n  \"meta\": {\n    \"company\": \"Acme\",\n    \"plan\": \"gold\"\n  }\n}"
            }
          },
          "response": [
            {
              "name": "200 OK (single)",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"contact\": {\n    \"id\": \"683554c596937cc4b90f5cf8\",\n    \"list_id\": \"683554c596937cc4b90f5cf7\",\n    \"number\": \"61412333555\",\n    \"first_name\": \"Jane\",\n    \"last_name\": \"Smith\",\n    \"email\": \"jane@example.com\",\n    \"meta\": {\n      \"company\": \"Acme\",\n      \"plan\": \"gold\"\n    }\n  },\n  \"message\": \"Contact created\"\n}"
            },
            {
              "name": "200 OK (batch)",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"created\": 2,\n  \"failed\": 1,\n  \"results\": [\n    { \"index\": 0, \"id\": \"683554c596937cc4b90f5cf8\" },\n    { \"index\": 1, \"id\": \"683554c596937cc4b90f5cf9\" },\n    { \"index\": 2, \"error\": \"Invalid contact object\" }\n  ],\n  \"message\": \"Batch processed\"\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Missing required field: list_id\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "List Contacts",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/contacts",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "contacts"
              ],
              "query": [
                {
                  "key": "list_id",
                  "value": "",
                  "description": "Optional. Restrict to one list (24-hex).",
                  "disabled": true
                },
                {
                  "key": "search",
                  "value": "",
                  "description": "Optional. Case-insensitive substring match on first name, last name, number, or email.",
                  "disabled": true
                },
                {
                  "key": "after",
                  "value": "",
                  "description": "24-hex cursor — the `id` of the last contact on the previous page.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "",
                  "description": "Page size. Plain list: 1–1000 (default 100). Search: 1–500 (default 500).",
                  "disabled": true
                }
              ]
            },
            "description": "List contacts, newest first, or search them.\n\n- **Without `search`:** a keyset-paginated list, optionally filtered by `list_id`.\n- **With `search`:** a substring match over name / number / email, also keyset-paginated.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `contacts` | array | Contacts on this page. |\n| `contacts[].id` | string | Contact id. |\n| `contacts[].list_id` | string | Owning list id. |\n| `contacts[].number` | string | Phone number (614… format). |\n| `contacts[].first_name` | string | First name. |\n| `contacts[].last_name` | string | Last name. |\n| `contacts[].email` | string | Email address. |\n| `contacts[].meta` | object | Custom fields (empty object when none). |\n| `count` | integer | Contacts on this page. |\n| `next_page` | string | Relative path for the next page; empty when there are no further results. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid list ID format` | 400 | `list_id` is not a 24-hex value. |\n| `Failed (Invalid Page)` | 400 | `after` is not a valid 24-hex cursor. |\n\n#### Notes\n- Plain-list page size defaults to 100 (`limit` 1–1000). Search page size defaults to 500 (`limit` 1–500).\n- `next_page` is present only when a full page was returned; follow it until it is empty. The paging examples below use `limit=2` to stay short.\n- Search is inherently a substring scan — for a rare term over a very large contact book a page may take longer to fill.",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"contacts\": [\n    {\n      \"id\": \"683554c596937cc4b90f5cf8\",\n      \"list_id\": \"683554c596937cc4b90f5cf7\",\n      \"number\": \"61412333555\",\n      \"first_name\": \"Jane\",\n      \"last_name\": \"Smith\",\n      \"email\": \"jane@example.com\",\n      \"meta\": {\n        \"company\": \"Acme\"\n      }\n    },\n    {\n      \"id\": \"683554c596937cc4b90f5cf6\",\n      \"list_id\": \"683554c596937cc4b90f5cf7\",\n      \"number\": \"61412333777\",\n      \"first_name\": \"Tom\",\n      \"last_name\": \"Jones\",\n      \"email\": \"tom@example.com\",\n      \"meta\": {}\n    }\n  ],\n  \"count\": 2,\n  \"next_page\": \"/api/v5/contacts?after=683554c596937cc4b90f5cf6\"\n}"
            },
            {
              "name": "200 OK (Last Page)",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"contacts\": [\n    {\n      \"id\": \"683554c596937cc4b90f5cf4\",\n      \"list_id\": \"683554c596937cc4b90f5cf7\",\n      \"number\": \"61412333999\",\n      \"first_name\": \"Amy\",\n      \"last_name\": \"Lee\",\n      \"email\": \"amy@example.com\",\n      \"meta\": {}\n    }\n  ],\n  \"count\": 1,\n  \"next_page\": \"\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Get Contact",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/contacts/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "contacts",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Contact id (24-hex)."
                }
              ]
            },
            "description": "Get a single contact by id.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `contact` | object | The contact: `id`, `list_id`, `number`, `first_name`, `last_name`, `email`, `meta`. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid contact ID format` | 400 | The id is not a 24-hex value. |\n| `Contact not found` | 400 | No such contact on this account. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"contact\": {\n    \"id\": \"683554c596937cc4b90f5cf8\",\n    \"list_id\": \"683554c596937cc4b90f5cf7\",\n    \"number\": \"61412333555\",\n    \"first_name\": \"Jane\",\n    \"last_name\": \"Smith\",\n    \"email\": \"jane@example.com\",\n    \"meta\": {\n      \"company\": \"Acme\"\n    }\n  }\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Contact not found\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Update Contact",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/contacts/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "contacts",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Contact id (24-hex)."
                }
              ]
            },
            "description": "Update fields on a contact. Only the fields you send change.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `number` | string | No | Phone number; normalised to 614… on save. |\n| `first_name` | string | No | First name. |\n| `last_name` | string | No | Last name. |\n| `email` | string | No | Email address. |\n| `meta` | object | No | Custom fields. **Replaces** the entire meta object — send the full desired set, not a partial patch. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `contact` | object | The updated contact. |\n| `message` | string | Confirmation message. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid contact ID format` | 400 | The id is not a 24-hex value. |\n| `Contact not found` | 400 | No such contact on this account. |\n| `Nothing to update` | 400 | No recognised field supplied. |\n\n#### Notes\n- `meta` is replaced wholesale, not merged; omit it to leave custom fields untouched.",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"email\": \"jane.smith@example.com\"\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"contact\": {\n    \"id\": \"683554c596937cc4b90f5cf8\",\n    \"list_id\": \"683554c596937cc4b90f5cf7\",\n    \"number\": \"61412333555\",\n    \"first_name\": \"Jane\",\n    \"last_name\": \"Smith\",\n    \"email\": \"jane.smith@example.com\",\n    \"meta\": {\n      \"company\": \"Acme\"\n    }\n  },\n  \"message\": \"Contact updated\"\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Nothing to update\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Delete Contact",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/contacts/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "contacts",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Contact id (24-hex)."
                }
              ]
            },
            "description": "Delete a contact.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `message` | string | Confirmation message. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid contact ID format` | 400 | The id is not a 24-hex value. |\n| `Contact not found` | 400 | No such contact on this account. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"message\": \"Contact deleted\"\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Contact not found\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Webhooks",
      "description": "Manage outbound webhook configurations programmatically. Webhooks POST a payload to your URL when a platform event fires. The six event types are `sms_events`, `sms_inbound`, `sms_optout`, `email_inbound`, `email_events`, `account_balance`. `email_events` webhooks additionally subscribe to a subset of `delivery`, `engagement`, and `unsubscribe` sub-events via the `events` array. All endpoints use `{{base_url_sms}}`.",
      "item": [
        {
          "name": "List Webhooks",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/webhooks",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "webhooks"
              ],
              "query": [
                {
                  "key": "type",
                  "value": "",
                  "description": "Optional. Restrict to one type: `sms_events`, `sms_inbound`, `sms_optout`, `email_inbound`, `email_events`, `account_balance`.",
                  "disabled": true
                }
              ]
            },
            "description": "List every outbound webhook configuration on your account, including disabled and temporarily-suppressed ones (this is a management view). Optionally filter by `type`.\n\n#### Query parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `type` | string | No | Restrict to one type. One of `sms_events`, `sms_inbound`, `sms_optout`, `email_inbound`, `email_events`, `account_balance`. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `webhooks` | array | Webhook configurations on the account. |\n| `webhooks[].id` | string | Webhook id (24-hex). |\n| `webhooks[].type` | string | One of `sms_events`, `sms_inbound`, `sms_optout`, `email_inbound`, `email_events`, `account_balance`. |\n| `webhooks[].url` | string | Destination URL the payload is POSTed to. |\n| `webhooks[].version` | integer | Payload format version. Currently always `1` (form-encoded); v2/JSON creation is disabled. |\n| `webhooks[].threshold` | integer\\|null | Balance threshold; set only for `account_balance` webhooks, otherwise `null`. |\n| `webhooks[].events` | array | Subscribed events; populated only for `email_events` webhooks (subset of `delivery`, `engagement`, `unsubscribe`), otherwise `[]`. |\n| `webhooks[].enabled` | boolean | Whether the webhook is currently enabled. |\n| `count` | integer | Number of webhooks returned. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid type. Must be one of: sms_events, sms_inbound, sms_optout, email_inbound, email_events, account_balance` | 400 | `type` filter is not an allowed value. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"webhooks\": [\n    {\n      \"id\": \"683554c596937cc4b90f5cf7\",\n      \"type\": \"sms_events\",\n      \"url\": \"https://example.com/dlr\",\n      \"version\": 1,\n      \"threshold\": null,\n      \"events\": [],\n      \"enabled\": true\n    },\n    {\n      \"id\": \"7a1b2c3d4e5f60718293a4b5\",\n      \"type\": \"email_events\",\n      \"url\": \"https://example.com/email-events\",\n      \"version\": 1,\n      \"threshold\": null,\n      \"events\": [\n        \"delivery\",\n        \"engagement\"\n      ],\n      \"enabled\": true\n    }\n  ],\n  \"count\": 2\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Create Webhook",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/webhooks",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "webhooks"
              ]
            },
            "description": "Create an outbound webhook configuration. The `type` determines which platform event fires it. Duplicate configurations of the same type are allowed.\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `type` | string | Yes | One of `sms_events`, `sms_inbound`, `sms_optout`, `email_inbound`, `email_events`, `account_balance`. |\n| `url` | string | Yes | Destination URL. `http://` is prepended if no scheme is given. Loopback and the cloud metadata address are rejected. |\n| `threshold` | integer | Conditional | Required for `type=account_balance`: fires when the account balance is at or below this value (must be > 0). Ignored for other types. |\n| `events` | array | Conditional | Required for `type=email_events`: a non-empty subset of `delivery`, `engagement`, `unsubscribe`. Duplicates are collapsed. Ignored for other types. |\n\nWebhooks are created as v1 (form-encoded payloads); v2/JSON creation is currently disabled.\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `webhook` | object | The created webhook (`id`, `type`, `url`, `version`, `threshold`, `events`, `enabled`). |\n| `message` | string | Confirmation message. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Missing required field: type` | 400 | `type` not supplied. |\n| `Invalid type. Must be one of: sms_events, sms_inbound, sms_optout, email_inbound, email_events, account_balance` | 400 | `type` is not an allowed value. |\n| `Missing required field: url` | 400 | `url` not supplied. |\n| `Balance webhooks require a numeric threshold greater than 0` | 400 | `type=account_balance` with a missing or non-positive `threshold`. |\n| `Email webhooks require a non-empty events array (subset of: delivery, engagement, unsubscribe)` | 400 | `type=email_events` with `events` absent, not an array, or empty. |\n| `Invalid event. Must be one of: delivery, engagement, unsubscribe` | 400 | `type=email_events` with an `events` value outside the allowlist. |\n| `Invalid URL format` | 400 | `url` fails URL validation. |\n| `URL must use http or https protocol` | 400 | `url` scheme is not http/https. |\n| `URL must have a valid domain` | 400 | `url` has no host. |\n| `Invalid URL protocol` | 400 | `url` contains a `file://` protocol. |\n| `Cannot use localhost URLs` | 400 | `url` host is localhost/127.0.0.1/::1. |\n| `Invalid URL` | 400 | `url` targets the cloud metadata address (169.254.169.254). |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"type\": \"email_events\",\n  \"url\": \"https://example.com/email-events\",\n  \"events\": [\n    \"delivery\",\n    \"engagement\"\n  ]\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"webhook\": {\n    \"id\": \"7a1b2c3d4e5f60718293a4b5\",\n    \"type\": \"email_events\",\n    \"url\": \"https://example.com/email-events\",\n    \"version\": 1,\n    \"threshold\": null,\n    \"events\": [\n      \"delivery\",\n      \"engagement\"\n    ],\n    \"enabled\": true\n  },\n  \"message\": \"Webhook created\"\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Email webhooks require a non-empty events array (subset of: delivery, engagement, unsubscribe)\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Enable / Disable Webhook",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/webhooks/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "webhooks",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Webhook id (24-hex)."
                }
              ]
            },
            "description": "Enable or disable an existing webhook by id. This is the only mutation on an existing webhook; `url`, `type`, and `events` are immutable (delete and recreate to change them).\n\n#### Path parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `id` | string | Yes | Webhook id (24-hex). |\n\n#### Request body parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `enabled` | boolean | Yes | `true` to enable, `false` to disable. |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `webhook` | object | The updated webhook. |\n| `message` | string | Confirmation message. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid webhook ID format` | 400 | `id` is not a valid 24-hex id. |\n| `Missing required field: enabled` | 400 | `enabled` not supplied. |\n| `Webhook not found` | 400 | No such webhook on this account. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{\n  \"enabled\": false\n}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"webhook\": {\n    \"id\": \"683554c596937cc4b90f5cf7\",\n    \"type\": \"sms_events\",\n    \"url\": \"https://example.com/dlr\",\n    \"version\": 1,\n    \"threshold\": null,\n    \"events\": [],\n    \"enabled\": false\n  },\n  \"message\": \"Webhook disabled\"\n}"
            },
            {
              "name": "400 Bad Request",
              "code": 400,
              "status": "Bad Request",
              "body": "{\n  \"error\": \"Webhook not found\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        },
        {
          "name": "Delete Webhook",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url_sms}}/webhooks/:id",
              "host": [
                "{{base_url_sms}}"
              ],
              "path": [
                "webhooks",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "",
                  "description": "Webhook id (24-hex)."
                }
              ]
            },
            "description": "Delete a webhook configuration by id.\n\n#### Path parameters\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `id` | string | Yes | Webhook id (24-hex). |\n\n#### Response fields\n| Field | Type | Description |\n| --- | --- | --- |\n| `error` | string | Empty on success. |\n| `message` | string | Confirmation message. |\n\n#### Errors\n| Error | HTTP | Cause |\n| --- | --- | --- |\n| `Invalid webhook ID format` | 400 | `id` is not a valid 24-hex id. |\n| `Webhook not found` | 400 | No such webhook on this account. |",
            "body": {
              "mode": "raw",
              "options": {
                "raw": {
                  "language": "json"
                }
              },
              "raw": "{}"
            }
          },
          "response": [
            {
              "name": "200 OK",
              "code": 200,
              "status": "OK",
              "body": "{\n  \"error\": \"\",\n  \"message\": \"Webhook deleted\"\n}"
            },
            {
              "name": "401 Unauthorized",
              "code": 401,
              "status": "Unauthorized",
              "body": "{\n  \"error\": \"Failed (Invalid API ID or Key)\"\n}"
            }
          ]
        }
      ]
    }
  ]
}
