{
    "openapi": "3.0.3",
    "info": {
        "title": "SMS Manager API",
        "description": "REST API powering SMS Manager v2. All endpoints return JSON.\n\n## Authentication\n\nThe API accepts two auth mechanisms. Both use the same header — only the value differs:\n\n```\nAuthorization: Bearer <your_api_key_or_jwt>\n```\n\n| Type | Lifespan | Best for |\n|------|----------|----------|\n| **API key** | Long-lived (until you revoke it) | Server-to-server integrations — backend services, scheduled jobs, scripts. **This is what the Quickstart uses.** Manage keys at [/v2/api_keys](https://smsmanager.com.au/v2/api_keys). |\n| **JWT bearer token** | Short-lived (per user session) | Obtained by exchanging email and password at `POST /auth/login`. Used by the SMS Manager web UI itself. Rarely the right choice for an external integration. |\n\n**Protect your API key.** Anyone with it can send messages on your account and incur charges. Treat it like a password — never commit it to source control or expose it in client-side code.\n\n## Quickstart\n\nSend your first SMS in three steps. You'll need an [SMS Manager account](https://smsmanager.com.au/v2/register).\n\n### 1. Get an API key\n\nGo to [API Keys](https://smsmanager.com.au/v2/api_keys), click *Create New Key*, give it a name, and copy the value.\n\n### 2. Send an SMS\n\n`POST /sms/send` — replace `YOUR_API_KEY` with your key and `+61400000000` with your mobile number in [E.164 format](https://en.wikipedia.org/wiki/E.164). **This sends a real message and costs 1 credit per segment.**\n\n```bash\ncurl -X POST https://smsmanager.com.au/v2/api/sms/send \\\n  -H \"Authorization: Bearer YOUR_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"message\": \"Hello from SMS Manager!\",\n    \"recipients\": [{\"type\": \"number\", \"value\": \"+61400000000\"}]\n  }'\n```\n\nResponse:\n\n```json\n{\n  \"success\": true,\n  \"message\": \"SMS queued for delivery successfully\",\n  \"data\": {\n    \"message_ref\": 109094230000,\n    \"sender_id\": \"YourBrand\",\n    \"recipients_count\": 1,\n    \"cost_per_recipient\": 1,\n    \"total_cost\": 1,\n    \"message_type\": \"SMS\",\n    \"encoding\": \"GSM7\",\n    \"segments\": 1,\n    \"status\": \"queued\"\n  },\n  \"timestamp\": \"2026-05-30T10:30:00+11:00\"\n}\n```\n\nHold onto `data.message_ref` — Step 3 uses it. `data.sender_id` may be `null` if your account doesn't have a default sender ID set, and `data.status` is the string `queued` for immediate sends or `scheduled` for future-dated sends.\n\n**Common errors.** `401` = check your `Authorization` header. `400` = check the recipient is E.164 (starts with `+`, includes country code).\n\n### 3. Check delivery status\n\n`GET /sms/status/{message_ref}` — poll this to see how delivery is going.\n\n```bash\ncurl https://smsmanager.com.au/v2/api/sms/status/109094230000 \\\n  -H \"Authorization: Bearer YOUR_API_KEY\"\n```\n\nResponse:\n\n```json\n{\n  \"success\": true,\n  \"message\": \"Message status retrieved successfully\",\n  \"data\": {\n    \"message_ref\": 109094230000,\n    \"status\": \"success\",\n    \"message\": \"Hello from SMS Manager!\",\n    \"sender_id\": \"YourBrand\",\n    \"total_recipients\": 1,\n    \"sent_count\": 1,\n    \"failed_count\": 0,\n    \"pending_count\": 0,\n    \"date_sent\": \"2026-05-30T15:33:46+10:00\"\n  },\n  \"timestamp\": \"2026-05-30T10:30:05+11:00\"\n}\n```\n\n`data.status` is the overall message status:\n\n| Value | Meaning |\n|-------|---------|\n| `\"queued\"` | Accepted, awaiting delivery |\n| `\"success\"` | All recipients delivered |\n| `\"failed\"` | All recipients failed |\n| `\"partial_success\"` | Some delivered, some failed |\n\n`sent_count` / `failed_count` / `pending_count` aggregate the per-recipient outcomes. `sender_id` and `date_sent` may be `null` until the message has been queued for delivery.\n\nFor push-based delivery receipts instead of polling, use webhooks (below).\n\n## Webhooks\n\nConfigure webhook endpoints at [/v2/webhooks](https://smsmanager.com.au/v2/webhooks). Three event types are POSTed to your URL:\n\n### Incoming SMS (`sms_mo`)\n\n```json\n{\n  \"hook_id\": 12421,\n  \"event_type\": \"sms_mo\",\n  \"timestamp\": \"2026-05-30T10:30:00+11:00\",\n  \"from\": \"61412345678\",\n  \"to\": \"61481070240\",\n  \"message\": \"Hello, this is a test message\"\n}\n```\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `hook_id` | integer | Unique event ID for this transaction |\n| `event_type` | string | Always `sms_mo` for incoming SMS |\n| `timestamp` | string | ISO 8601 timestamp with timezone |\n| `from` | string | Sender's phone number (E.164 format) |\n| `to` | string | Your SMS Manager number (E.164 format) |\n| `message` | string | The SMS text content |\n\n### Incoming MMS (`mms_mo`)\n\n```json\n{\n  \"hook_id\": 12421,\n  \"event_type\": \"mms_mo\",\n  \"timestamp\": \"2026-05-30T10:35:00+11:00\",\n  \"from\": \"61412345678\",\n  \"to\": \"61481070240\",\n  \"message\": \"Check out this photo\",\n  \"images\": [\n    \"https://smsmanager.com.au/images/logo1.gif\",\n    \"https://smsmanager.com.au/images/logo2.png\"\n  ]\n}\n```\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `hook_id` | integer | Unique event ID for this transaction |\n| `event_type` | string | Always `mms_mo` for incoming MMS |\n| `message` | string | MMS text content (optional) |\n| `images` | array | Array of image URLs |\n\n### Delivery Receipt (`dlr`)\n\n```json\n{\n  \"hook_id\": 12421,\n  \"event_type\": \"dlr\",\n  \"timestamp\": \"2026-05-30T10:32:00+11:00\",\n  \"message_ref\": \"SM5678\",\n  \"from\": \"YourBrand\",\n  \"to\": \"61412345678\",\n  \"status_code\": \"Delivered\"\n}\n```\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `hook_id` | integer | Unique event ID for this transaction |\n| `event_type` | string | Always `dlr` for delivery receipts |\n| `message_ref` | string | Your original message reference from SMS Manager |\n| `from` | string | Sender ID used for the original message |\n| `to` | string | The recipient's phone number |\n| `status_code` | string | Delivery status (`Delivered`, `Failed`, `Expired`, etc.) |",
        "version": "2.0.0"
    },
    "servers": [
        {
            "url": "https://smsmanager.com.au/v2/api",
            "description": "Production"
        }
    ],
    "security": [
        {
            "bearerAuth": []
        }
    ],
    "tags": [
        {
            "name": "Account",
            "description": "Manage the logged-in user's personal account: settings, two-factor authentication, and account closure."
        },
        {
            "name": "Account Sharing",
            "description": "Multi-user access for a single account. Invite team members, manage their permissions and roles, list shared accounts you have access to, and switch the active account context."
        },
        {
            "name": "API Keys",
            "description": "Create, list, and revoke API keys for server-to-server authentication. Each key acts as a long-lived bearer token scoped to your account."
        },
        {
            "name": "Authentication",
            "description": "Email/password login, JWT refresh and verification, account registration, and the forgot-password flow. Most external integrations should use API Keys instead."
        },
        {
            "name": "Auto Top-Up",
            "description": "Configure automatic credit purchases when your balance drops below a threshold. Requires a stored card on file."
        },
        {
            "name": "Automations",
            "description": "Webhook subscriptions tailored for third-party automation platforms like Zapier. Provides sample payloads and platform-aware event delivery, distinct from the lower-level Webhooks endpoints."
        },
        {
            "name": "Billing",
            "description": "Purchase credits, view invoice and credit history, render invoices, and run NAB-backed card payment flows (stored card, pre-auth, bulk payment)."
        },
        {
            "name": "Blocked Numbers",
            "description": "Maintain a per-account block list of phone numbers that should never receive messages. Supports single and bulk operations and tracks how each entry was added (manual, SMS STOP, or web opt-out)."
        },
        {
            "name": "Cards",
            "description": "Manage the stored credit card used for top-ups and one-off purchases. Backed by NAB Periodic for tokenised storage."
        },
        {
            "name": "Chats",
            "description": "Two-way conversation view aggregating inbound and outbound SMS per contact. Mark conversations read, star, archive, or block at the conversation level."
        },
        {
            "name": "Config",
            "description": "Runtime client-side configuration (feature flags, limits, server timezone). Consumed by the SMS Manager web UI."
        },
        {
            "name": "Contacts",
            "description": "CRUD for contacts plus bulk delete, clone, and export. Filter by group, blocked status, owner pool, or custom field values. Custom field definitions are managed separately."
        },
        {
            "name": "Discounts",
            "description": "Validate promo and discount codes at checkout. Promo codes top up free credits; discount codes apply a percentage discount and may be first-purchase-only."
        },
        {
            "name": "Feedback",
            "description": "Submit user feedback or bug reports from inside the app."
        },
        {
            "name": "Groups",
            "description": "Contact groups and group memberships. Includes group-level metadata, member listings, bulk member management, and per-member activate/deactivate flags used to skip recipients on send."
        },
        {
            "name": "Import",
            "description": "Multi-step contact import from a file or pasted data: parse, validate, then execute (with optional Server-Sent Events progress). Also supports a single-request import for smaller datasets."
        },
        {
            "name": "Interactive",
            "description": "Auto-reply rules. Configure keyword triggers that match inbound SMS against `contains`/`is`/`begins with`/`ends with` patterns and send an automated reply."
        },
        {
            "name": "MMS",
            "description": "Public-facing slide rendering for MMS messages. Serves the binary content of a stored MMS slide by hash and display order."
        },
        {
            "name": "Messages",
            "description": "Search and retrieval over the full incoming and outgoing message history, including per-message details, recipient breakdowns, replies, statistics, and CSV export."
        },
        {
            "name": "News",
            "description": "Customer-facing news feed shown on the SMS Manager dashboard. Mark items as viewed to clear \"new\" badges."
        },
        {
            "name": "Numbers",
            "description": "Manage incoming phone numbers. Search the available pool, request a number, cancel/reactivate, and pay the initial-period fee."
        },
        {
            "name": "Scheduled",
            "description": "Manage scheduled and recurring messages. Pause, resume, send-now, edit, or cancel. Inspect recipient lists and per-recipient delivery progress."
        },
        {
            "name": "SMS",
            "description": "Send SMS and MMS messages, look up delivery status, list send history, and cancel scheduled sends."
        },
        {
            "name": "Search",
            "description": "Quick search across contacts and groups by name or phone number, returning a mixed result list."
        },
        {
            "name": "Routing",
            "description": "Per-destination-country routing rules for non-standard traffic. Block traffic to a country, or replace the Sender ID (unconditionally or only when unverified) per country and message type. The mandatory Australian overstamp always applies after these rules."
        },
        {
            "name": "Sender IDs",
            "description": "Manage custom sender IDs (alphanumeric or numeric) used for outbound messages. Submit, list, edit, delete, and check carrier approval status."
        },
        {
            "name": "Templates",
            "description": "Save reusable message templates. Each template is a title plus a stored message body for quick reuse on the send screen."
        },
        {
            "name": "Users",
            "description": "Manage the authenticated user's profile, credit balance, sub-accounts, and per-user preferences. Includes sub-account creation, credit transfers, and email/password change flows."
        },
        {
            "name": "Webhooks",
            "description": "Outbound HTTP webhooks for delivery receipts, inbound SMS/MMS, and other events. Configure target URLs and payload format."
        }
    ],
    "paths": {
        "/account/2fa/setup": {
            "get": {
                "summary": "Begin 2FA setup",
                "description": "Generates (or returns the existing) Google Authenticator secret for the effective account and returns a QR code URL for provisioning. Requires manage_account permission when acting on a shared account. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Account"
                ],
                "responses": {
                    "200": {
                        "description": "2FA setup payload",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "secret": {
                                                    "type": "string",
                                                    "description": "Base32 TOTP secret."
                                                },
                                                "qr_url": {
                                                    "type": "string",
                                                    "description": "URL to a Google Chart QR code encoding the otpauth URI."
                                                },
                                                "manual_entry_key": {
                                                    "type": "string",
                                                    "description": "Same value as `secret`, for manual entry into an authenticator app."
                                                },
                                                "issuer": {
                                                    "type": "string",
                                                    "example": "BulkSMS"
                                                },
                                                "account_name": {
                                                    "type": "string",
                                                    "example": "BulkSMS:user@example.com"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/account/2fa/enable": {
            "post": {
                "summary": "Enable 2FA",
                "description": "Verifies the supplied TOTP code against the supplied secret and, on success, marks 2FA enabled on the effective account. Requires manage_account permission when acting on a shared account. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Account"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "secret",
                                    "code"
                                ],
                                "properties": {
                                    "secret": {
                                        "type": "string",
                                        "description": "Base32 TOTP secret returned from /account/2fa/setup."
                                    },
                                    "code": {
                                        "type": "string",
                                        "pattern": "^[0-9]{6}$",
                                        "description": "6-digit code from the authenticator app."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "2FA enabled",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message": {
                                                    "type": "string",
                                                    "example": "Two-factor authentication enabled successfully"
                                                },
                                                "enabled": {
                                                    "type": "boolean",
                                                    "example": true
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                }
            }
        },
        "/account/2fa/disable": {
            "post": {
                "summary": "Disable 2FA",
                "description": "Verifies the supplied TOTP code against the stored secret and disables 2FA on the effective account. Requires manage_account permission when acting on a shared account. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Account"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "code"
                                ],
                                "properties": {
                                    "code": {
                                        "type": "string",
                                        "pattern": "^[0-9]{6}$",
                                        "description": "6-digit code from the authenticator app, used to confirm the user controls the second factor before disabling it."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "2FA disabled",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message": {
                                                    "type": "string",
                                                    "example": "Two-factor authentication disabled successfully"
                                                },
                                                "enabled": {
                                                    "type": "boolean",
                                                    "example": false
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                }
            }
        },
        "/account/settings": {
            "get": {
                "summary": "Get account settings",
                "description": "Returns the effective account's SMS-reply, low-credit, 2FA, firewall, and opt-out settings, plus the caller's current IP. Requires manage_account permission when acting on a shared account. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Account"
                ],
                "responses": {
                    "200": {
                        "description": "Account settings",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "settings": {
                                                    "type": "object",
                                                    "properties": {
                                                        "sms_replies_to": {
                                                            "type": "array",
                                                            "items": {
                                                                "type": "string",
                                                                "format": "email"
                                                            },
                                                            "description": "Email addresses that receive SMS replies."
                                                        },
                                                        "minimum_credits": {
                                                            "type": "integer",
                                                            "description": "Low-credit warning threshold; defaults to 100 when unset."
                                                        },
                                                        "use_ga": {
                                                            "type": "boolean",
                                                            "description": "Whether Google Authenticator 2FA is enabled."
                                                        },
                                                        "use_firewall": {
                                                            "type": "boolean"
                                                        },
                                                        "firewall_ips": {
                                                            "type": "array",
                                                            "items": {
                                                                "type": "string"
                                                            },
                                                            "description": "Allowed IP addresses or CIDR network ranges (IPv4 or IPv6) when the firewall is enabled. A request IP matches if it equals an entry or falls within a CIDR range, e.g. \"203.0.113.5\", \"203.0.113.0/24\" or \"2001:db8::/32\"."
                                                        },
                                                        "optout_message": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "auto_block_on_optout": {
                                                            "type": "boolean",
                                                            "description": "When true (default), opting out adds the recipient to the block list. When false, opt-outs still deactivate the contact from groups but do not block the number."
                                                        },
                                                        "current_ip": {
                                                            "type": "string",
                                                            "description": "The caller's remote IP, for adding to firewall_ips."
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "post": {
                "summary": "Update account settings",
                "description": "Update one or more account settings. Only the supplied fields are changed. Requires manage_account permission when acting on a shared account. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Account"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "sms_replies_to": {
                                        "description": "Either an array of emails or a comma-separated string.",
                                        "oneOf": [
                                            {
                                                "type": "array",
                                                "items": {
                                                    "type": "string"
                                                }
                                            },
                                            {
                                                "type": "string"
                                            }
                                        ]
                                    },
                                    "use_firewall": {
                                        "type": "boolean"
                                    },
                                    "minimum_credits": {
                                        "type": "integer",
                                        "minimum": 0
                                    },
                                    "firewall_ips": {
                                        "description": "Allowed IP addresses or CIDR network ranges (IPv4 or IPv6), as either an array or a newline-separated string. Each entry must be a valid IP (e.g. \"203.0.113.5\", \"2001:db8::1\") or CIDR range (e.g. \"203.0.113.0/24\", \"2001:db8::/32\"); any malformed entry rejects the whole request with 400 and no changes are saved.",
                                        "oneOf": [
                                            {
                                                "type": "array",
                                                "items": {
                                                    "type": "string"
                                                }
                                            },
                                            {
                                                "type": "string"
                                            }
                                        ]
                                    },
                                    "optout_message": {
                                        "type": "string"
                                    },
                                    "auto_block_on_optout": {
                                        "type": "boolean",
                                        "description": "When true (default), opting out adds the recipient to the block list. When false, opt-outs still deactivate the contact from groups but do not block the number."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                }
            }
        },
        "/account/close": {
            "post": {
                "summary": "Close account",
                "description": "Marks the logged-in user's account as expired, bumps token_version (invalidating existing JWTs), and appends a closure note to the user's comments. Always operates on the authenticated user's own account, not the assumed context. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Account"
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "405": {
                        "$ref": "#/components/responses/MethodNotAllowed"
                    }
                }
            }
        },
        "/account/members": {
            "get": {
                "summary": "List team members and invitations",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Get all team members and pending invitations for the effective account. Requires owner role or manage_members permission. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "responses": {
                    "200": {
                        "description": "Members and pending invitations",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "members": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/AccountMember"
                                                    }
                                                },
                                                "invitations": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/AccountInvitation"
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                }
            }
        },
        "/account/members/{member_id}": {
            "put": {
                "summary": "Update member permissions",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Update the permissions for a team member. At least one permission must be enabled. Requires owner role or manage_members permission. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "parameters": [
                    {
                        "name": "member_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "The team_member_id of the member to update."
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "permissions"
                                ],
                                "properties": {
                                    "permissions": {
                                        "$ref": "#/components/schemas/AccountPermissions"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "patch": {
                "summary": "Update member permissions (alias)",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Same behaviour as PUT /account/members/{member_id} — the handler accepts either method. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "parameters": [
                    {
                        "name": "member_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "permissions"
                                ],
                                "properties": {
                                    "permissions": {
                                        "$ref": "#/components/schemas/AccountPermissions"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "delete": {
                "summary": "Remove team member",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Remove a team member from the effective account. Requires owner role or manage_members permission. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "parameters": [
                    {
                        "name": "member_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/account/invitations": {
            "get": {
                "summary": "List pending invitations",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Get all pending invitations for the effective account. Requires owner role or manage_members permission. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "responses": {
                    "200": {
                        "description": "Pending invitations",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "invitations": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/AccountInvitation"
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                }
            },
            "post": {
                "summary": "Invite team member",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Send an invitation to a new team member. If `permissions` is omitted the default guest permission set is used. Requires owner role or manage_members permission. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "email"
                                ],
                                "properties": {
                                    "email": {
                                        "type": "string",
                                        "format": "email"
                                    },
                                    "permissions": {
                                        "$ref": "#/components/schemas/AccountPermissions"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Invitation created and emailed",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Invitation sent successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "invitation_id": {
                                                    "type": "integer"
                                                },
                                                "email": {
                                                    "type": "string",
                                                    "format": "email"
                                                },
                                                "expires_at": {
                                                    "type": "string",
                                                    "format": "date-time"
                                                },
                                                "email_sent": {
                                                    "type": "boolean"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                }
            }
        },
        "/account/invitations/accept": {
            "post": {
                "summary": "Accept an invitation",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Accept a team-share invitation using the token from the invitation email. The accepting user's email must match the invited email. No special permission is required. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "token"
                                ],
                                "properties": {
                                    "token": {
                                        "type": "string",
                                        "description": "The invitation token from the invitation email."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Invitation accepted",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Invitation accepted successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "account_user_id": {
                                                    "type": "integer"
                                                },
                                                "account_name": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/account/invitations/{invitation_id}": {
            "put": {
                "summary": "Update invitation permissions",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Update the permissions on a pending invitation. At least one permission must be enabled. Requires owner role or manage_members permission. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "parameters": [
                    {
                        "name": "invitation_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "permissions"
                                ],
                                "properties": {
                                    "permissions": {
                                        "$ref": "#/components/schemas/AccountPermissions"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "patch": {
                "summary": "Update invitation permissions (alias)",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Same behaviour as PUT /account/invitations/{invitation_id} — the handler accepts either method. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "parameters": [
                    {
                        "name": "invitation_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "permissions"
                                ],
                                "properties": {
                                    "permissions": {
                                        "$ref": "#/components/schemas/AccountPermissions"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "delete": {
                "summary": "Cancel invitation",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Revoke a pending invitation. Requires owner role or manage_members permission. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "parameters": [
                    {
                        "name": "invitation_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/account/invitations/{invitation_id}/resend": {
            "post": {
                "summary": "Resend invitation",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Extend the invitation's expiration by seven days and re-send the invitation email. Requires owner role or manage_members permission. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "parameters": [
                    {
                        "name": "invitation_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Invitation resent",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Invitation resent successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "invitation_id": {
                                                    "type": "integer"
                                                },
                                                "email": {
                                                    "type": "string",
                                                    "format": "email"
                                                },
                                                "expires_at": {
                                                    "type": "string",
                                                    "format": "date-time"
                                                },
                                                "email_sent": {
                                                    "type": "boolean"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/account/shared": {
            "get": {
                "summary": "List shared accounts",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Get accounts the authenticated user has been granted guest access to (excludes the user's own and subaccounts). Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "responses": {
                    "200": {
                        "description": "Shared accounts",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "type": "object",
                                                "properties": {
                                                    "account_user_id": {
                                                        "type": "integer"
                                                    },
                                                    "owner_name": {
                                                        "type": "string"
                                                    },
                                                    "owner_email": {
                                                        "type": "string"
                                                    },
                                                    "role": {
                                                        "type": "string",
                                                        "enum": [
                                                            "guest"
                                                        ]
                                                    },
                                                    "account_status": {
                                                        "type": "string",
                                                        "nullable": true
                                                    },
                                                    "permissions": {
                                                        "$ref": "#/components/schemas/AccountPermissions"
                                                    },
                                                    "created_at": {
                                                        "type": "string",
                                                        "format": "date-time",
                                                        "nullable": true
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "405": {
                        "$ref": "#/components/responses/MethodNotAllowed"
                    }
                }
            }
        },
        "/account/switch": {
            "post": {
                "summary": "Switch account context",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Switch the active account context to another accessible account (own, subaccount, or shared). Returns a new JWT and the resolved account info. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "account_user_id"
                                ],
                                "properties": {
                                    "account_user_id": {
                                        "type": "integer",
                                        "description": "The user_id of the account to switch to (use own user_id for own account)."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Switched account context",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "token": {
                                                    "type": "string",
                                                    "description": "New JWT token with the updated account context."
                                                },
                                                "account": {
                                                    "type": "object",
                                                    "properties": {
                                                        "user_id": {
                                                            "type": "integer"
                                                        },
                                                        "name": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "role": {
                                                            "type": "string",
                                                            "enum": [
                                                                "owner",
                                                                "guest"
                                                            ]
                                                        },
                                                        "permissions": {
                                                            "oneOf": [
                                                                {
                                                                    "$ref": "#/components/schemas/AccountPermissions"
                                                                },
                                                                {
                                                                    "type": "null"
                                                                }
                                                            ],
                                                            "description": "Null for owner contexts."
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "405": {
                        "$ref": "#/components/responses/MethodNotAllowed"
                    }
                }
            }
        },
        "/account/leave": {
            "post": {
                "summary": "Leave shared account",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Remove the authenticated user from a shared account. If the user was currently viewing the account they are leaving, a fresh JWT scoped to their own account is returned. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "account_user_id"
                                ],
                                "properties": {
                                    "account_user_id": {
                                        "type": "integer",
                                        "description": "The user_id of the account to leave."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Left the account",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Successfully left the account"
                                        },
                                        "data": {
                                            "type": "object",
                                            "nullable": true,
                                            "description": "Null when the leave does not require a context switch; otherwise an object with the fields below.",
                                            "properties": {
                                                "token": {
                                                    "type": "string",
                                                    "description": "New JWT scoped to the user's own account."
                                                },
                                                "switched_to_own_account": {
                                                    "type": "boolean"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "405": {
                        "$ref": "#/components/responses/MethodNotAllowed"
                    }
                }
            }
        },
        "/account/accessible": {
            "get": {
                "summary": "List accessible accounts",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Get every account the authenticated user can access: their own, any subaccounts they own, and any accounts shared with them. The currently-active account is flagged on each entry and summarised under `current_account`. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "responses": {
                    "200": {
                        "description": "Accessible accounts",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "current_account": {
                                                    "type": "object",
                                                    "nullable": true,
                                                    "properties": {
                                                        "user_id": {
                                                            "type": "integer"
                                                        },
                                                        "name": {
                                                            "type": "string"
                                                        },
                                                        "role": {
                                                            "type": "string",
                                                            "enum": [
                                                                "owner",
                                                                "guest"
                                                            ]
                                                        },
                                                        "kind": {
                                                            "type": "string",
                                                            "enum": [
                                                                "own",
                                                                "subaccount",
                                                                "guest"
                                                            ]
                                                        }
                                                    }
                                                },
                                                "accounts": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "user_id": {
                                                                "type": "integer"
                                                            },
                                                            "name": {
                                                                "type": "string"
                                                            },
                                                            "email": {
                                                                "type": "string"
                                                            },
                                                            "role": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "owner",
                                                                    "guest"
                                                                ]
                                                            },
                                                            "kind": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "own",
                                                                    "subaccount",
                                                                    "guest"
                                                                ]
                                                            },
                                                            "account_status": {
                                                                "type": "string",
                                                                "nullable": true
                                                            },
                                                            "permissions": {
                                                                "oneOf": [
                                                                    {
                                                                        "$ref": "#/components/schemas/AccountPermissions"
                                                                    },
                                                                    {
                                                                        "type": "null"
                                                                    }
                                                                ],
                                                                "description": "Null for owner/subaccount entries."
                                                            },
                                                            "is_current": {
                                                                "type": "boolean"
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/account/permissions": {
            "get": {
                "summary": "Get available permissions",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Get the catalogue of permission keys and human-readable descriptions, plus the default guest permission set used when an invitation does not specify permissions. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "responses": {
                    "200": {
                        "description": "Available permissions",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "permissions": {
                                                    "type": "object",
                                                    "description": "Map of permission key to description.",
                                                    "additionalProperties": {
                                                        "type": "string"
                                                    }
                                                },
                                                "defaults": {
                                                    "$ref": "#/components/schemas/AccountPermissions"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/account/my-invitations": {
            "get": {
                "summary": "Get my pending invitations",
                "tags": [
                    "Account Sharing"
                ],
                "description": "Get pending invitations addressed to the authenticated user's email. These are invitations from other accounts that the user can accept via /account/invitations/accept. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "responses": {
                    "200": {
                        "description": "Pending invitations addressed to the user",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "invitations": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "invitation_id": {
                                                                "type": "integer"
                                                            },
                                                            "token": {
                                                                "type": "string"
                                                            },
                                                            "account_user_id": {
                                                                "type": "integer"
                                                            },
                                                            "owner_name": {
                                                                "type": "string"
                                                            },
                                                            "owner_email": {
                                                                "type": "string"
                                                            },
                                                            "permissions": {
                                                                "$ref": "#/components/schemas/AccountPermissions"
                                                            },
                                                            "created_at": {
                                                                "type": "string",
                                                                "format": "date-time"
                                                            },
                                                            "expires_at": {
                                                                "type": "string",
                                                                "format": "date-time"
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "405": {
                        "$ref": "#/components/responses/MethodNotAllowed"
                    }
                }
            }
        },
        "/apikeys": {
            "get": {
                "summary": "List API keys",
                "description": "Returns all API keys belonging to the authenticated account (or the active sub-account context). The full `api_key` value is returned alongside a masked version for display; usage stats (`hits`, `last_used`) are included. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "API Keys"
                ],
                "responses": {
                    "200": {
                        "description": "API keys retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "description": "Array of API keys.",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "api_key_id": {
                                                                "type": "integer"
                                                            },
                                                            "user_id": {
                                                                "type": "integer"
                                                            },
                                                            "api_key": {
                                                                "type": "string",
                                                                "description": "Full API key value (prefixed `sk_`)."
                                                            },
                                                            "api_key_masked": {
                                                                "type": "string",
                                                                "description": "Masked form `xxxxxxxx...yyyy` for display."
                                                            },
                                                            "name": {
                                                                "type": "string"
                                                            },
                                                            "created": {
                                                                "type": "string",
                                                                "format": "date-time",
                                                                "nullable": true
                                                            },
                                                            "last_used": {
                                                                "type": "string",
                                                                "format": "date-time",
                                                                "nullable": true
                                                            },
                                                            "hits": {
                                                                "type": "integer",
                                                                "description": "Number of times this key has been used."
                                                            }
                                                        }
                                                    }
                                                },
                                                "total": {
                                                    "type": "integer",
                                                    "description": "Count of returned API keys."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "post": {
                "summary": "Create API key",
                "description": "Generates a new secure API key (prefixed `sk_`) bound to the authenticated account. Returns the full key value once on creation. The account is limited to 10 active API keys. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "API Keys"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "description": "Human-readable label for the API key. Whitespace is trimmed; empty strings are rejected."
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "API key created successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "object",
                                                    "properties": {
                                                        "api_key_id": {
                                                            "type": "integer"
                                                        },
                                                        "api_key": {
                                                            "type": "string",
                                                            "description": "Full API key value, shown only at creation time."
                                                        },
                                                        "name": {
                                                            "type": "string"
                                                        },
                                                        "created": {
                                                            "type": "string",
                                                            "format": "date-time"
                                                        },
                                                        "message": {
                                                            "type": "string",
                                                            "description": "Per-record success message."
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "delete": {
                "summary": "Delete API key (ID required)",
                "description": "Always returns 400. The handler requires an API key ID in the path; calling `DELETE /apikeys` without an ID is rejected. Use `DELETE /apikeys/{id}` instead. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "API Keys"
                ],
                "responses": {
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    }
                }
            }
        },
        "/apikeys/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "API key ID."
                }
            ],
            "get": {
                "summary": "Get API key",
                "description": "Returns a single API key owned by the authenticated account, including the full `api_key` value, a masked version, and usage stats. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "API Keys"
                ],
                "responses": {
                    "200": {
                        "description": "API key retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "object",
                                                    "properties": {
                                                        "api_key_id": {
                                                            "type": "integer"
                                                        },
                                                        "user_id": {
                                                            "type": "integer"
                                                        },
                                                        "api_key": {
                                                            "type": "string"
                                                        },
                                                        "api_key_masked": {
                                                            "type": "string"
                                                        },
                                                        "name": {
                                                            "type": "string"
                                                        },
                                                        "created": {
                                                            "type": "string",
                                                            "format": "date-time",
                                                            "nullable": true
                                                        },
                                                        "last_used": {
                                                            "type": "string",
                                                            "format": "date-time",
                                                            "nullable": true
                                                        },
                                                        "hits": {
                                                            "type": "integer"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "delete": {
                "summary": "Delete API key",
                "description": "Permanently removes an API key owned by the authenticated account. Subsequent requests using that key will be rejected. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "API Keys"
                ],
                "responses": {
                    "200": {
                        "description": "API key deleted successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message": {
                                                    "type": "string",
                                                    "description": "`API key deleted successfully`."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/auth/login": {
            "post": {
                "summary": "Log in",
                "tags": [
                    "Authentication"
                ],
                "description": "Authenticate with email, password, and optional 2FA token to receive a JWT. Accepts JSON or form-encoded bodies. When `remember_me` is true the issued token uses the extended expiry from configuration.",
                "security": [],
                "responses": {
                    "200": {
                        "description": "Login successful.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Login successful"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "token": {
                                                    "type": "string",
                                                    "description": "JWT bearer token."
                                                },
                                                "token_type": {
                                                    "type": "string",
                                                    "example": "Bearer"
                                                },
                                                "expires_in": {
                                                    "type": "integer",
                                                    "description": "Token lifetime in seconds. Uses `jwt_remember_me_expiry` config when `remember_me` was true, otherwise `jwt_expiry`."
                                                },
                                                "user": {
                                                    "type": "object",
                                                    "properties": {
                                                        "email": {
                                                            "type": "string",
                                                            "format": "email"
                                                        },
                                                        "name": {
                                                            "type": "string"
                                                        },
                                                        "company": {
                                                            "type": "string"
                                                        },
                                                        "access_level": {
                                                            "type": "string",
                                                            "description": "Role name from the `access` table (e.g. `client`, `admin`, `reseller`)."
                                                        },
                                                        "credit_balance": {
                                                            "type": "number",
                                                            "format": "float",
                                                            "description": "Displayable credit balance (parent's balance if user shares credits)."
                                                        },
                                                        "uses_parent_credits": {
                                                            "type": "boolean"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "email",
                                    "password"
                                ],
                                "properties": {
                                    "email": {
                                        "type": "string",
                                        "format": "email"
                                    },
                                    "password": {
                                        "type": "string",
                                        "format": "password"
                                    },
                                    "token": {
                                        "type": "string",
                                        "description": "Optional 6 digit 2FA code. If 2FA is enabled and omitted, a 422 with `message: 'Please provide your 2FA token'` is returned."
                                    },
                                    "remember_me": {
                                        "type": "boolean",
                                        "default": false
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/auth/logout": {
            "post": {
                "summary": "Log out",
                "tags": [
                    "Authentication"
                ],
                "description": "Records a logout audit entry for the bearer token's user, if the token is valid. JWTs are stateless so clients must also discard the token locally. Always returns 200 with `data: null`.",
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    }
                }
            }
        },
        "/auth/refresh": {
            "post": {
                "summary": "Refresh token",
                "tags": [
                    "Authentication"
                ],
                "description": "Verifies the current JWT in the Authorization header and issues a new one with the standard (non-remember-me) expiry.",
                "responses": {
                    "200": {
                        "description": "New token issued.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Token refreshed successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "token": {
                                                    "type": "string"
                                                },
                                                "token_type": {
                                                    "type": "string",
                                                    "example": "Bearer"
                                                },
                                                "expires_in": {
                                                    "type": "integer",
                                                    "description": "Token lifetime in seconds (`jwt_expiry` config)."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/auth/verify": {
            "get": {
                "summary": "Verify JWT or API key",
                "tags": [
                    "Authentication"
                ],
                "description": "Validate a JWT token or API key in the Authorization header and return user context. Tokens matching `sk_[A-Za-z0-9_-]+` are treated as API keys; everything else is treated as a JWT.",
                "responses": {
                    "200": {
                        "description": "Token or API key is valid",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Jwt is valid"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "valid": {
                                                    "type": "boolean",
                                                    "example": true
                                                },
                                                "auth_type": {
                                                    "type": "string",
                                                    "enum": [
                                                        "jwt",
                                                        "api_key"
                                                    ],
                                                    "description": "Type of authentication used"
                                                },
                                                "user": {
                                                    "type": "object",
                                                    "properties": {
                                                        "email": {
                                                            "type": "string",
                                                            "format": "email"
                                                        },
                                                        "name": {
                                                            "type": "string"
                                                        },
                                                        "company": {
                                                            "type": "string"
                                                        },
                                                        "access_level": {
                                                            "type": "string"
                                                        },
                                                        "credit_balance": {
                                                            "type": "number",
                                                            "format": "float"
                                                        },
                                                        "uses_parent_credits": {
                                                            "type": "boolean"
                                                        }
                                                    }
                                                },
                                                "expires_at": {
                                                    "type": "string",
                                                    "format": "date-time",
                                                    "description": "JWT expiration time (only for JWT auth)"
                                                },
                                                "api_key_id": {
                                                    "type": "integer",
                                                    "description": "API key ID (only for API key auth)"
                                                },
                                                "api_key_name": {
                                                    "type": "string",
                                                    "description": "API key name (only for API key auth)"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                },
                                "examples": {
                                    "jwt": {
                                        "summary": "JWT Token Verification",
                                        "value": {
                                            "success": true,
                                            "message": "Jwt is valid",
                                            "data": {
                                                "valid": true,
                                                "auth_type": "jwt",
                                                "user": {
                                                    "email": "user@example.com",
                                                    "name": "John Doe",
                                                    "company": "ACME Corp",
                                                    "access_level": "client",
                                                    "credit_balance": 150.5,
                                                    "uses_parent_credits": false
                                                },
                                                "expires_at": "2025-10-20T12:00:00+11:00"
                                            }
                                        }
                                    },
                                    "api_key": {
                                        "summary": "API Key Verification",
                                        "value": {
                                            "success": true,
                                            "message": "Api_key is valid",
                                            "data": {
                                                "valid": true,
                                                "auth_type": "api_key",
                                                "user": {
                                                    "email": "user@example.com",
                                                    "name": "John Doe",
                                                    "company": "ACME Corp",
                                                    "access_level": "client",
                                                    "credit_balance": 150.5,
                                                    "uses_parent_credits": false
                                                },
                                                "api_key_id": 3,
                                                "api_key_name": "Production API Key"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/auth/register": {
            "post": {
                "summary": "Register account",
                "tags": [
                    "Authentication"
                ],
                "description": "Register a new self-service account. Only `name`, `email`, `password`, `password_confirm`, and `terms` are required by the handler; other fields are optional metadata used during account setup, fraud scoring, and welcome emails.",
                "security": [],
                "responses": {
                    "200": {
                        "description": "Registration succeeded.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "user_id": {
                                                    "type": "integer"
                                                },
                                                "email_verification_required": {
                                                    "type": "boolean"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name",
                                    "email",
                                    "password",
                                    "password_confirm",
                                    "terms"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "description": "Contact person's full name."
                                    },
                                    "email": {
                                        "type": "string",
                                        "format": "email"
                                    },
                                    "password": {
                                        "type": "string",
                                        "format": "password",
                                        "minLength": 8
                                    },
                                    "password_confirm": {
                                        "type": "string",
                                        "format": "password",
                                        "description": "Must match `password`."
                                    },
                                    "terms": {
                                        "type": "boolean",
                                        "description": "Must be true (T&C acceptance)."
                                    },
                                    "mobile": {
                                        "type": "string",
                                        "description": "Optional. Normalized to AU format and stored as `gsm_number`."
                                    },
                                    "suburb": {
                                        "type": "string",
                                        "description": "Optional. Used by the MinFraud check and stored in user comments."
                                    },
                                    "state": {
                                        "type": "string",
                                        "description": "Optional. Stored in user comments when fraud check is disabled."
                                    },
                                    "how_found": {
                                        "type": "string",
                                        "description": "Optional 'How did you hear about us?' answer, stored in user comments."
                                    },
                                    "promotional_code": {
                                        "type": "string",
                                        "description": "Optional promo code from the `discounts_promotions` table; replaces the default free credit grant when valid."
                                    },
                                    "password_setup_required": {
                                        "type": "boolean",
                                        "description": "Optional flag stored in user comments to indicate the password must be set up later."
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/auth/forgot-password": {
            "post": {
                "summary": "Request password reset",
                "tags": [
                    "Authentication"
                ],
                "description": "Emails a 6 digit verification code to the supplied address if it matches an active account. Responds with a generic success message regardless of whether the email exists, to avoid leaking account existence. Banned accounts receive an explicit suspension error.",
                "security": [],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "email"
                                ],
                                "properties": {
                                    "email": {
                                        "type": "string",
                                        "format": "email"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/auth/reset-password": {
            "post": {
                "summary": "Reset password",
                "tags": [
                    "Authentication"
                ],
                "description": "Completes a password reset using the 6 digit code emailed by `/auth/forgot-password`. The code is valid for 15 minutes. On success the user's password is replaced and the reset token is cleared.",
                "security": [],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "email",
                                    "code",
                                    "password"
                                ],
                                "properties": {
                                    "email": {
                                        "type": "string",
                                        "format": "email"
                                    },
                                    "code": {
                                        "type": "string",
                                        "pattern": "^[0-9]{6}$"
                                    },
                                    "password": {
                                        "type": "string",
                                        "format": "password",
                                        "minLength": 8
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/automations/subscribe": {
            "post": {
                "summary": "Subscribe to automation events",
                "description": "Create a new automation platform subscription (Zapier, n8n, Make, Pipedream, etc.) for receiving real-time event notifications via webhook. The target URL must be HTTPS. Users are limited to 20 total subscriptions and 5 per event type. A backing webhook record is created automatically.",
                "tags": [
                    "Automations"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "target_url",
                                    "event_type"
                                ],
                                "properties": {
                                    "target_url": {
                                        "type": "string",
                                        "format": "uri",
                                        "description": "HTTPS webhook URL where events will be POSTed (must use HTTPS)",
                                        "example": "https://hooks.zapier.com/hooks/catch/123456/abcdef/"
                                    },
                                    "event_type": {
                                        "type": "string",
                                        "enum": [
                                            "sms_mo",
                                            "mms_mo",
                                            "dlr"
                                        ],
                                        "description": "Event type to trigger on: sms_mo (incoming SMS), mms_mo (incoming MMS), dlr (delivery receipts)"
                                    },
                                    "platform": {
                                        "type": "string",
                                        "default": "zapier",
                                        "description": "Automation platform identifier. Defaults to `zapier` when omitted. Not enum-validated by the handler.",
                                        "example": "zapier",
                                        "enum": [
                                            "zapier",
                                            "n8n",
                                            "make",
                                            "pipedream",
                                            "manual",
                                            "other"
                                        ]
                                    },
                                    "external_id": {
                                        "type": "string",
                                        "description": "Platform-specific identifier (e.g., Zapier zap_id, n8n workflow_id)",
                                        "example": "12345"
                                    },
                                    "metadata": {
                                        "type": "object",
                                        "description": "Additional platform-specific data (JSON-encoded and stored as a string)",
                                        "example": {
                                            "workflow_name": "SMS to Slack",
                                            "created_by": "user@example.com"
                                        }
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Subscription created successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Subscription created successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "subscription_id": {
                                                    "type": "integer",
                                                    "description": "Unique subscription identifier",
                                                    "example": 1
                                                },
                                                "webhook_id": {
                                                    "type": "integer",
                                                    "description": "Associated webhook ID",
                                                    "example": 5
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Subscription limit exceeded (max 20 per user, or max 5 per event type)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "422": {
                        "description": "Validation error (missing/invalid target_url or event_type)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/automations/unsubscribe/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Subscription ID to delete"
                }
            ],
            "delete": {
                "summary": "Unsubscribe from automation events",
                "description": "Delete an automation subscription. This stops all webhook deliveries for the subscription. If this was the only subscription using the associated webhook, the webhook record is also deleted.",
                "tags": [
                    "Automations"
                ],
                "responses": {
                    "200": {
                        "description": "Subscription deleted successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Subscription deleted successfully"
                                        },
                                        "data": {
                                            "type": "null"
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/automations/subscriptions": {
            "get": {
                "summary": "List automation subscriptions",
                "description": "Returns all automation subscriptions for the authenticated user, ordered by `created` descending. Supports optional filtering by `platform` and/or `event_type`. Does not paginate.",
                "tags": [
                    "Automations"
                ],
                "parameters": [
                    {
                        "name": "platform",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "zapier",
                                "n8n",
                                "make",
                                "pipedream",
                                "manual",
                                "other"
                            ]
                        },
                        "description": "Filter by automation platform"
                    },
                    {
                        "name": "event_type",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "sms_mo",
                                "mms_mo",
                                "dlr"
                            ]
                        },
                        "description": "Filter by event type"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Successful response",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Subscriptions retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "subscriptions": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/AutomationSubscription"
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/automations/subscriptions/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Subscription ID"
                }
            ],
            "get": {
                "summary": "Get automation subscription",
                "description": "Returns the details and delivery statistics for a specific automation subscription owned by the authenticated user.",
                "tags": [
                    "Automations"
                ],
                "responses": {
                    "200": {
                        "description": "Successful response",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Subscription retrieved successfully"
                                        },
                                        "data": {
                                            "$ref": "#/components/schemas/AutomationSubscription"
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/automations/samples/{event_type}": {
            "parameters": [
                {
                    "name": "event_type",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "enum": [
                            "sms_mo",
                            "mms_mo",
                            "dlr"
                        ]
                    },
                    "description": "Event type to get sample data for"
                }
            ],
            "get": {
                "summary": "Get sample event data",
                "description": "Returns hardcoded sample payloads for an event type. Used by automation platforms (like Zapier) during app setup and testing. Does not require authentication. Note: this endpoint returns a raw JSON array (not the standard `{success, message, data, timestamp}` envelope) because Zapier requires array-format sample data.",
                "tags": [
                    "Automations"
                ],
                "security": [],
                "responses": {
                    "200": {
                        "description": "Sample data in array format (not wrapped in standard response envelope)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "oneOf": [
                                            {
                                                "$ref": "#/components/schemas/WebhookPayloadSMSMO"
                                            },
                                            {
                                                "$ref": "#/components/schemas/WebhookPayloadMMSMO"
                                            },
                                            {
                                                "$ref": "#/components/schemas/WebhookPayloadDLR"
                                            }
                                        ]
                                    }
                                },
                                "examples": {
                                    "sms_mo": {
                                        "summary": "SMS MO sample",
                                        "value": [
                                            {
                                                "hook_id": 12421,
                                                "event_type": "sms_mo",
                                                "timestamp": "2025-01-15T10:30:00+11:00",
                                                "from": "61412345678",
                                                "to": "61481070240",
                                                "message": "Hello, this is a test message"
                                            }
                                        ]
                                    },
                                    "mms_mo": {
                                        "summary": "MMS MO sample",
                                        "value": [
                                            {
                                                "hook_id": 12421,
                                                "event_type": "mms_mo",
                                                "timestamp": "2025-01-15T10:35:00+11:00",
                                                "from": "61412345678",
                                                "to": "61481070240",
                                                "message": "Check out this photo",
                                                "images": [
                                                    "https://smsmanager.com.au/images/logo1.gif",
                                                    "https://smsmanager.com.au/images/logo2.png"
                                                ]
                                            }
                                        ]
                                    },
                                    "dlr": {
                                        "summary": "DLR sample",
                                        "value": [
                                            {
                                                "hook_id": 12421,
                                                "event_type": "dlr",
                                                "message_ref": "111876640000",
                                                "timestamp": "2025-01-15T10:32:00+11:00",
                                                "from": "YourBrand",
                                                "to": "61412345678",
                                                "status_code": "Delivered"
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    }
                }
            }
        },
        "/autotopup/settings": {
            "get": {
                "summary": "Get auto top-up settings",
                "description": "Retrieve current auto top-up configuration for the authenticated user including enabled status, threshold, package, daily maximum, and the stored card display info (masked PAN, expiry, holder name, type) joined from `nab_periodic`. If no autotopup row exists yet, defaults are returned along with any card on file. Subaccounts that use parent credits receive 403.",
                "tags": [
                    "Auto Top-Up"
                ],
                "responses": {
                    "200": {
                        "description": "Autotopup settings retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Autotopup settings retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "autotopup_id": {
                                                    "type": "integer",
                                                    "nullable": true,
                                                    "description": "Null when no settings row exists yet."
                                                },
                                                "user_id": {
                                                    "type": "integer"
                                                },
                                                "enabled": {
                                                    "type": "boolean"
                                                },
                                                "threshold": {
                                                    "type": "integer",
                                                    "description": "Credit threshold that triggers a top-up (0 = only when out of credits)."
                                                },
                                                "package_id": {
                                                    "type": "integer",
                                                    "nullable": true
                                                },
                                                "daily_max": {
                                                    "type": "number",
                                                    "format": "float",
                                                    "description": "Maximum amount to charge per day in dollars (0 = no limit)."
                                                },
                                                "nab_pan": {
                                                    "type": "string",
                                                    "nullable": true,
                                                    "description": "Masked card PAN (last 4 visible)."
                                                },
                                                "card_expiry": {
                                                    "type": "string",
                                                    "nullable": true,
                                                    "description": "Card expiry as stored in `nab_periodic` (typically MMYY)."
                                                },
                                                "card_holder_name": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "card_type": {
                                                    "type": "string",
                                                    "nullable": true,
                                                    "description": "Card scheme (e.g. VISA, MC)."
                                                },
                                                "has_card": {
                                                    "type": "boolean",
                                                    "description": "True if a stored card exists for the user."
                                                },
                                                "created_at": {
                                                    "type": "string",
                                                    "format": "date-time",
                                                    "nullable": true
                                                },
                                                "updated_at": {
                                                    "type": "string",
                                                    "format": "date-time",
                                                    "nullable": true
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "description": "Subaccount using parent credits cannot access autotopup APIs."
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "post": {
                "summary": "Save auto top-up settings",
                "description": "Upsert the authenticated user's auto top-up configuration. Requires `threshold` and `package_id`; `enabled` and `daily_max` default to `false`/`0` when omitted. Enabling requires `users.ccapproval = 1` (at least one approved purchase). Disabling cancels any pending/processing/failed `autotopup_attempts` rows with a `next_retry_at`. A stored card is managed via the `/cards` endpoint and is not modified here.",
                "tags": [
                    "Auto Top-Up"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "threshold",
                                    "package_id"
                                ],
                                "properties": {
                                    "enabled": {
                                        "type": "boolean",
                                        "default": false,
                                        "description": "Enable or disable auto top-up."
                                    },
                                    "threshold": {
                                        "type": "integer",
                                        "minimum": 0,
                                        "description": "Credit threshold that triggers auto top-up (0 = only when completely out of credits)."
                                    },
                                    "package_id": {
                                        "type": "integer",
                                        "minimum": 1,
                                        "description": "Credit package ID to purchase when triggered. Must be a package owned by the user or a public package (`packages.user_id = 0`)."
                                    },
                                    "daily_max": {
                                        "type": "number",
                                        "format": "float",
                                        "minimum": 0,
                                        "default": 0,
                                        "description": "Maximum amount to charge per day in dollars (0 = no limit)."
                                    }
                                }
                            },
                            "examples": {
                                "enable": {
                                    "summary": "Enable auto top-up",
                                    "value": {
                                        "enabled": true,
                                        "threshold": 100,
                                        "package_id": 5,
                                        "daily_max": 50
                                    }
                                },
                                "disable": {
                                    "summary": "Disable auto top-up",
                                    "value": {
                                        "enabled": false,
                                        "threshold": 0,
                                        "package_id": 1,
                                        "daily_max": 0
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Settings saved successfully. `data` is `null`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Autotopup settings saved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "nullable": true,
                                            "example": null
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "description": "Returned when the caller is a subaccount using parent credits, or when enabling without an approved first purchase (`users.ccapproval = 0`)."
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/billing/packages": {
            "get": {
                "summary": "List credit packages",
                "description": "Returns all public credit packages (origin='i', user_id=0) available for purchase, along with billing conditions text shown on the pricing page. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Billing"
                ],
                "responses": {
                    "200": {
                        "description": "Packages retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "packages": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "id": {
                                                                "type": "integer"
                                                            },
                                                            "credits": {
                                                                "type": "integer",
                                                                "description": "Credits per package unit."
                                                            },
                                                            "cost_per_credit": {
                                                                "type": "number"
                                                            },
                                                            "total_cost": {
                                                                "type": "number",
                                                                "description": "credits * cost_per_credit."
                                                            },
                                                            "notes": {
                                                                "type": "string",
                                                                "nullable": true
                                                            },
                                                            "discount": {
                                                                "type": "integer",
                                                                "description": "Discount percentage."
                                                            },
                                                            "bonus": {
                                                                "type": "integer",
                                                                "description": "Bonus credit percentage."
                                                            }
                                                        }
                                                    }
                                                },
                                                "conditions": {
                                                    "type": "object",
                                                    "properties": {
                                                        "gst_note": {
                                                            "type": "string"
                                                        },
                                                        "expiry": {
                                                            "type": "string"
                                                        },
                                                        "delivery_tracking": {
                                                            "type": "string"
                                                        },
                                                        "sms_replies": {
                                                            "type": "string"
                                                        },
                                                        "payment_options": {
                                                            "type": "string"
                                                        },
                                                        "invoice_note": {
                                                            "type": "string"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/billing/history": {
            "get": {
                "summary": "Credit purchase history",
                "description": "Lists the user's credit history records (invoices, top-ups, adjustments) with linked invoice and discount details. Supports status and date-range filters; date filters are interpreted in the supplied IANA timezone before being converted to server time. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Billing"
                ],
                "parameters": [
                    {
                        "name": "page",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "default": 1
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "minimum": 10,
                            "maximum": 100,
                            "default": 25
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "awaiting",
                                "approval",
                                "freebie",
                                "credited",
                                "adjustment",
                                "pending",
                                "paid",
                                "cancelled",
                                "refunded"
                            ]
                        },
                        "description": "Filter by status. 'awaiting' matches empty/null status; 'adjustment' matches negative credit rows; others match credit_history.status exactly."
                    },
                    {
                        "name": "date_from",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Start date/time (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS) in the supplied timezone."
                    },
                    {
                        "name": "date_to",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "End date/time (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS) in the supplied timezone."
                    },
                    {
                        "name": "timezone",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "default": "Australia/Melbourne"
                        },
                        "description": "IANA timezone identifier used to interpret date filters."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Credit history retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "history": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "credit_history_id": {
                                                                "type": "integer"
                                                            },
                                                            "credits": {
                                                                "type": "integer"
                                                            },
                                                            "cost_per_credit": {
                                                                "type": "number"
                                                            },
                                                            "original_cost": {
                                                                "type": "number"
                                                            },
                                                            "discount_amount": {
                                                                "type": "number"
                                                            },
                                                            "total_cost": {
                                                                "type": "number"
                                                            },
                                                            "gst_percentage": {
                                                                "type": "number"
                                                            },
                                                            "gst_amount": {
                                                                "type": "number"
                                                            },
                                                            "total_with_gst": {
                                                                "type": "number"
                                                            },
                                                            "datetime": {
                                                                "type": "string",
                                                                "format": "date-time"
                                                            },
                                                            "status": {
                                                                "type": "string",
                                                                "nullable": true
                                                            },
                                                            "origin": {
                                                                "type": "string"
                                                            },
                                                            "discount_code": {
                                                                "type": "string",
                                                                "nullable": true
                                                            },
                                                            "discount_description": {
                                                                "type": "string",
                                                                "nullable": true
                                                            },
                                                            "commission": {
                                                                "type": "number"
                                                            },
                                                            "invoice": {
                                                                "type": "object",
                                                                "nullable": true,
                                                                "properties": {
                                                                    "invoice_id": {
                                                                        "type": "string"
                                                                    },
                                                                    "user_name": {
                                                                        "type": "string"
                                                                    },
                                                                    "address": {
                                                                        "type": "string"
                                                                    },
                                                                    "suburb": {
                                                                        "type": "string"
                                                                    },
                                                                    "postcode": {
                                                                        "type": "string"
                                                                    },
                                                                    "state": {
                                                                        "type": "string"
                                                                    },
                                                                    "status": {
                                                                        "type": "string",
                                                                        "nullable": true
                                                                    },
                                                                    "total_ex_gst": {
                                                                        "type": "number"
                                                                    },
                                                                    "description": {
                                                                        "type": "string",
                                                                        "nullable": true
                                                                    },
                                                                    "paid_date": {
                                                                        "type": "string",
                                                                        "format": "date",
                                                                        "nullable": true
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                },
                                                "pagination": {
                                                    "type": "object",
                                                    "properties": {
                                                        "current_page": {
                                                            "type": "integer"
                                                        },
                                                        "total_pages": {
                                                            "type": "integer"
                                                        },
                                                        "total_records": {
                                                            "type": "integer"
                                                        },
                                                        "limit": {
                                                            "type": "integer"
                                                        },
                                                        "has_next": {
                                                            "type": "boolean"
                                                        },
                                                        "has_previous": {
                                                            "type": "boolean"
                                                        }
                                                    }
                                                },
                                                "filters": {
                                                    "type": "object",
                                                    "properties": {
                                                        "available_statuses": {
                                                            "type": "array",
                                                            "items": {
                                                                "type": "string"
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/billing/delete": {
            "delete": {
                "summary": "Delete unpaid invoice",
                "description": "Deletes a single credit_history row and its linked invoice if both are unpaid (empty status). Paid or processed invoices are rejected. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Billing"
                ],
                "parameters": [
                    {
                        "name": "credit_history_id",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer",
                            "minimum": 1
                        },
                        "description": "Credit history ID to delete."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Invoice deleted.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message": {
                                                    "type": "string"
                                                },
                                                "deleted_invoice": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "deleted_credit_history_id": {
                                                    "type": "integer"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/billing/bulk-delete": {
            "delete": {
                "summary": "Bulk delete unpaid invoices",
                "description": "Deletes multiple unpaid credit_history rows and their linked invoices in a single request. Paid or processed invoices are skipped and reported in the errors array. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Billing"
                ],
                "responses": {
                    "200": {
                        "description": "Bulk delete completed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message": {
                                                    "type": "string"
                                                },
                                                "deleted_count": {
                                                    "type": "integer"
                                                },
                                                "failed_count": {
                                                    "type": "integer"
                                                },
                                                "errors": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "string"
                                                    },
                                                    "description": "Only present when at least one deletion failed."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "credit_history_ids"
                                ],
                                "properties": {
                                    "credit_history_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "minItems": 1,
                                        "description": "Array of credit_history_id values to delete."
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/billing/checkout": {
            "post": {
                "summary": "Checkout cart (creates invoice + NAB form)",
                "description": "Creates a credit_history row plus an invoice for the cart and returns a NAB Transact payment form payload. Used by the unapproved-user (preauth) flow. Approved users should use /billing/validate-cart followed by /billing/pay-with-stored-card. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Billing"
                ],
                "responses": {
                    "200": {
                        "description": "Checkout processed and payment form generated.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message": {
                                                    "type": "string"
                                                },
                                                "invoices": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "string"
                                                    },
                                                    "description": "Created invoice IDs (currently a single entry)."
                                                },
                                                "total_credits": {
                                                    "type": "integer"
                                                },
                                                "total_amount": {
                                                    "type": "number",
                                                    "description": "Total including GST."
                                                },
                                                "payment_form": {
                                                    "type": "object",
                                                    "properties": {
                                                        "action": {
                                                            "type": "string",
                                                            "format": "uri"
                                                        },
                                                        "method": {
                                                            "type": "string",
                                                            "enum": [
                                                                "POST"
                                                            ]
                                                        },
                                                        "fields": {
                                                            "type": "object",
                                                            "additionalProperties": true
                                                        }
                                                    }
                                                },
                                                "redirect_to_payment": {
                                                    "type": "boolean"
                                                },
                                                "is_first_purchase": {
                                                    "type": "boolean",
                                                    "description": "True when the account had no prior completed purchase (no non-freebie credit_history row with positive credits), captured BEFORE this cart's credit_history row is written. The pre-auth (new-user) flow uses this value to fire the one-off GA4 first_purchase milestone event at card submission — the later /billing/preauth-card response cannot carry it because the row already exists by then."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad request. PROFILE_INCOMPLETE returns missing_fields and can_manage_account.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": false
                                        },
                                        "error": {
                                            "type": "string",
                                            "example": "PROFILE_INCOMPLETE"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "missing_fields": {
                                            "type": "array",
                                            "items": {
                                                "type": "string"
                                            }
                                        },
                                        "can_manage_account": {
                                            "type": "boolean"
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "cart"
                                ],
                                "properties": {
                                    "cart": {
                                        "type": "array",
                                        "items": {
                                            "type": "object",
                                            "required": [
                                                "packageId",
                                                "quantity"
                                            ],
                                            "properties": {
                                                "packageId": {
                                                    "type": "integer",
                                                    "minimum": 1
                                                },
                                                "quantity": {
                                                    "type": "integer",
                                                    "minimum": 1
                                                }
                                            },
                                            "additionalProperties": false
                                        },
                                        "minItems": 1
                                    },
                                    "discount_code": {
                                        "type": "string",
                                        "nullable": true
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                }
            }
        },
        "/billing/validate-cart": {
            "post": {
                "summary": "Validate cart without creating invoice",
                "description": "Validates cart items, applies any eligible discount code, and returns calculated totals without creating a credit_history or invoice row. Used to populate the payment modal before the user commits. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Billing"
                ],
                "responses": {
                    "200": {
                        "description": "Cart validated successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message": {
                                                    "type": "string"
                                                },
                                                "cart_valid": {
                                                    "type": "boolean"
                                                },
                                                "total_credits": {
                                                    "type": "integer"
                                                },
                                                "subtotal": {
                                                    "type": "number",
                                                    "description": "Cart subtotal before discount."
                                                },
                                                "discount_code": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "discount_percentage": {
                                                    "type": "integer"
                                                },
                                                "discount_amount": {
                                                    "type": "number"
                                                },
                                                "final_subtotal": {
                                                    "type": "number",
                                                    "description": "Subtotal after discount, before GST."
                                                },
                                                "gst_amount": {
                                                    "type": "number"
                                                },
                                                "total_amount": {
                                                    "type": "number",
                                                    "description": "Total including GST."
                                                },
                                                "description": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad request. PROFILE_INCOMPLETE returns missing_fields and can_manage_account.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": false
                                        },
                                        "error": {
                                            "type": "string",
                                            "example": "PROFILE_INCOMPLETE"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "missing_fields": {
                                            "type": "array",
                                            "items": {
                                                "type": "string"
                                            }
                                        },
                                        "can_manage_account": {
                                            "type": "boolean"
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "cart"
                                ],
                                "properties": {
                                    "cart": {
                                        "type": "array",
                                        "items": {
                                            "type": "object",
                                            "required": [
                                                "packageId",
                                                "quantity"
                                            ],
                                            "properties": {
                                                "packageId": {
                                                    "type": "integer",
                                                    "minimum": 1
                                                },
                                                "quantity": {
                                                    "type": "integer",
                                                    "minimum": 1
                                                }
                                            },
                                            "additionalProperties": false
                                        },
                                        "minItems": 1
                                    },
                                    "discount_code": {
                                        "type": "string",
                                        "nullable": true
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                }
            }
        },
        "/billing/generate-invoice": {
            "post": {
                "summary": "Generate invoice from cart (no payment)",
                "description": "Creates a credit_history row and an unpaid invoice for the cart without initiating payment. Used when the user wants an invoice to pay later (e.g. EFT). Discount codes are NOT applied by this endpoint. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Billing"
                ],
                "responses": {
                    "200": {
                        "description": "Invoice generated.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message": {
                                                    "type": "string"
                                                },
                                                "invoices": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "string"
                                                    },
                                                    "description": "Created invoice IDs (currently a single entry)."
                                                },
                                                "total_credits": {
                                                    "type": "integer"
                                                },
                                                "total_amount": {
                                                    "type": "number",
                                                    "description": "Total including GST."
                                                },
                                                "redirect_to_payment": {
                                                    "type": "boolean"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad request. PROFILE_INCOMPLETE returns missing_fields and can_manage_account.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": false
                                        },
                                        "error": {
                                            "type": "string",
                                            "example": "PROFILE_INCOMPLETE"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "missing_fields": {
                                            "type": "array",
                                            "items": {
                                                "type": "string"
                                            }
                                        },
                                        "can_manage_account": {
                                            "type": "boolean"
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "cart"
                                ],
                                "properties": {
                                    "cart": {
                                        "type": "array",
                                        "items": {
                                            "type": "object",
                                            "required": [
                                                "packageId",
                                                "quantity"
                                            ],
                                            "properties": {
                                                "packageId": {
                                                    "type": "integer",
                                                    "minimum": 1
                                                },
                                                "quantity": {
                                                    "type": "integer",
                                                    "minimum": 1
                                                }
                                            },
                                            "additionalProperties": false
                                        },
                                        "minItems": 1
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                }
            }
        },
        "/billing/payment": {
            "get": {
                "summary": "Payment details + NAB form for one invoice",
                "description": "Returns invoice totals and a NAB Transact payment form payload for a single unpaid invoice. Exactly one of invoice or transaction must be supplied. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Billing"
                ],
                "parameters": [
                    {
                        "name": "invoice",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Invoice ID (e.g. S042659)."
                    },
                    {
                        "name": "transaction",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Credit history ID."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Payment details returned.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "invoice": {
                                                    "type": "object",
                                                    "properties": {
                                                        "invoice_id": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "credit_history_id": {
                                                            "type": "integer"
                                                        },
                                                        "description": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "credits": {
                                                            "type": "integer"
                                                        },
                                                        "cost_per_credit": {
                                                            "type": "number"
                                                        },
                                                        "show_credits_columns": {
                                                            "type": "boolean"
                                                        },
                                                        "total_ex_gst": {
                                                            "type": "number"
                                                        },
                                                        "gst_amount": {
                                                            "type": "number"
                                                        },
                                                        "total_with_gst": {
                                                            "type": "number"
                                                        }
                                                    }
                                                },
                                                "payment_form": {
                                                    "type": "object",
                                                    "properties": {
                                                        "action": {
                                                            "type": "string",
                                                            "format": "uri"
                                                        },
                                                        "method": {
                                                            "type": "string",
                                                            "enum": [
                                                                "POST"
                                                            ]
                                                        },
                                                        "fields": {
                                                            "type": "object",
                                                            "additionalProperties": true
                                                        }
                                                    }
                                                },
                                                "user": {
                                                    "type": "object",
                                                    "properties": {
                                                        "name": {
                                                            "type": "string"
                                                        },
                                                        "email": {
                                                            "type": "string",
                                                            "format": "email"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad request. PROFILE_INCOMPLETE returns missing_fields.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": false
                                        },
                                        "error": {
                                            "type": "string",
                                            "example": "PROFILE_INCOMPLETE"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "missing_fields": {
                                            "type": "array",
                                            "items": {
                                                "type": "string"
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/billing/bulk-payment": {
            "post": {
                "summary": "Bulk payment details + NAB form",
                "description": "Returns aggregated invoice totals and a NAB Transact payment form payload covering multiple unpaid invoices. All invoices must belong to the current account. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Billing"
                ],
                "responses": {
                    "200": {
                        "description": "Bulk payment details returned.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "invoices": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "invoice_id": {
                                                                "type": "string"
                                                            },
                                                            "credit_history_id": {
                                                                "type": "integer"
                                                            },
                                                            "credits": {
                                                                "type": "integer"
                                                            },
                                                            "total_cost": {
                                                                "type": "number"
                                                            },
                                                            "gst_amount": {
                                                                "type": "number"
                                                            },
                                                            "total_with_gst": {
                                                                "type": "number"
                                                            }
                                                        }
                                                    }
                                                },
                                                "total_amount": {
                                                    "type": "number"
                                                },
                                                "payment_form": {
                                                    "type": "object",
                                                    "properties": {
                                                        "action": {
                                                            "type": "string",
                                                            "format": "uri"
                                                        },
                                                        "method": {
                                                            "type": "string",
                                                            "enum": [
                                                                "POST"
                                                            ]
                                                        },
                                                        "fields": {
                                                            "type": "object",
                                                            "additionalProperties": true
                                                        }
                                                    }
                                                },
                                                "user": {
                                                    "type": "object",
                                                    "properties": {
                                                        "name": {
                                                            "type": "string"
                                                        },
                                                        "email": {
                                                            "type": "string",
                                                            "format": "email"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad request, already-paid invoice, or PROFILE_INCOMPLETE.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": false
                                        },
                                        "error": {
                                            "type": "string"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "missing_fields": {
                                            "type": "array",
                                            "items": {
                                                "type": "string"
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "invoices"
                                ],
                                "properties": {
                                    "invoices": {
                                        "type": "array",
                                        "items": {
                                            "type": "string",
                                            "pattern": "^[SM]\\d{3,7}$",
                                            "description": "Invoice ID (S or M followed by 3-7 digits)."
                                        },
                                        "minItems": 1
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/billing/fingerprint": {
            "post": {
                "summary": "Generate NAB fingerprint",
                "description": "Computes an HMAC-SHA256 fingerprint for a NAB Hosted Payment Page payload. The payment_data object may include payment_reference, payment_alert, and any number of invoice-ID keys (pattern S######) whose values are the line amounts. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Billing"
                ],
                "responses": {
                    "200": {
                        "description": "Fingerprint generated.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "fingerprint": {
                                                    "type": "string"
                                                },
                                                "vendor_name": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "payment_data"
                                ],
                                "properties": {
                                    "payment_data": {
                                        "type": "object",
                                        "additionalProperties": true,
                                        "properties": {
                                            "payment_reference": {
                                                "type": "string"
                                            },
                                            "payment_alert": {
                                                "type": "string"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/billing/nab-transaction": {
            "post": {
                "summary": "NAB transaction callback (internal)",
                "description": "Internal callback from the NAB Hosted Payment Page. Verifies an HMAC plus single-use nonce, then credits the user and marks the invoices paid. Not for direct use; no JWT required.",
                "tags": [
                    "Billing"
                ],
                "security": [],
                "responses": {
                    "200": {
                        "description": "Acknowledged.",
                        "content": {
                            "text/plain": {
                                "schema": {
                                    "type": "string",
                                    "example": "OK"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Verification failed.",
                        "content": {
                            "text/plain": {
                                "schema": {
                                    "type": "string",
                                    "example": "Invalid signature"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "Processing error.",
                        "content": {
                            "text/plain": {
                                "schema": {
                                    "type": "string",
                                    "example": "ERROR: ..."
                                }
                            }
                        }
                    }
                },
                "requestBody": {
                    "required": false,
                    "description": "Form-encoded fields from NAB, plus the `hmac` and `nonce` we issued.",
                    "content": {
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "additionalProperties": true
                            }
                        }
                    }
                }
            }
        },
        "/billing/invoice/{invoice_id}": {
            "parameters": [
                {
                    "name": "invoice_id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string"
                    },
                    "description": "Invoice identifier (e.g. S042659)."
                }
            ],
            "get": {
                "summary": "View invoice (HTML)",
                "description": "Renders an HTML invoice page using inc/invoice_template.php. Returns HTML, not a JSON envelope. Error responses use the standard JSON error envelope. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Billing"
                ],
                "responses": {
                    "200": {
                        "description": "Rendered invoice HTML.",
                        "content": {
                            "text/html": {
                                "schema": {
                                    "type": "string"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/billing/preauth-card": {
            "post": {
                "summary": "Store credit card for new user approval",
                "description": "For NEW users with ccapproval=0. Validates the card (Luhn + expiry), stores it with NAB Transact Periodic API (CRN), mirrors it into nab_periodic, inserts a pending row into the cc table with a MaxMind fraud score, and notifies admin via email + SMS. Card is NOT charged - admin must approve the payment. American Express is rejected. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Billing"
                ],
                "responses": {
                    "200": {
                        "description": "Card stored, awaiting admin approval.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "payment_id": {
                                                    "type": "integer",
                                                    "description": "cc table primary key."
                                                },
                                                "message": {
                                                    "type": "string"
                                                },
                                                "masked_card": {
                                                    "type": "string",
                                                    "description": "****XXXX format."
                                                },
                                                "card_type": {
                                                    "type": "string",
                                                    "enum": [
                                                        "VISA",
                                                        "MC"
                                                    ]
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "cc_name",
                                    "cc_number",
                                    "expiry",
                                    "invoice_data"
                                ],
                                "properties": {
                                    "cc_name": {
                                        "type": "string",
                                        "description": "Cardholder name as it appears on card.",
                                        "minLength": 1
                                    },
                                    "cc_number": {
                                        "type": "string",
                                        "description": "Credit card number (13-19 digits, spaces allowed)."
                                    },
                                    "expiry": {
                                        "type": "string",
                                        "description": "Card expiry in MM/YY format.",
                                        "pattern": "^(0[1-9]|1[0-2])/[0-9]{2}$"
                                    },
                                    "invoice_data": {
                                        "type": "object",
                                        "description": "Invoice details for the pending payment. Accepts either {invoice:{invoice_id,total_with_gst}}, {invoice_id,total_with_gst}, or {invoices:[ids],total_amount}.",
                                        "additionalProperties": true,
                                        "properties": {
                                            "invoice": {
                                                "type": "object",
                                                "properties": {
                                                    "invoice_id": {
                                                        "type": "string"
                                                    },
                                                    "total_with_gst": {
                                                        "type": "number"
                                                    }
                                                }
                                            },
                                            "invoice_id": {
                                                "type": "string"
                                            },
                                            "total_with_gst": {
                                                "type": "number"
                                            },
                                            "invoices": {
                                                "type": "array",
                                                "items": {
                                                    "type": "string"
                                                }
                                            },
                                            "total_amount": {
                                                "type": "number"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/billing/pay-with-stored-card": {
            "post": {
                "summary": "Pay with stored card",
                "description": "For approved users (ccapproval>=1). Charges the user's stored card via NAB Transact Periodic API. Can pay existing invoices (invoice_ids) or create an invoice from cart and pay in one step (cart). When cart is provided, invoice is created atomically with the payment attempt - if payment fails after invoice creation the response includes invoice_created=true and invoice_id. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Billing"
                ],
                "responses": {
                    "200": {
                        "description": "Payment successful.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message": {
                                                    "type": "string"
                                                },
                                                "transaction_id": {
                                                    "type": "string",
                                                    "description": "NAB transaction ID."
                                                },
                                                "invoices_paid": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "string"
                                                    }
                                                },
                                                "total_amount": {
                                                    "type": "number",
                                                    "description": "Total amount charged including GST."
                                                },
                                                "credits_added": {
                                                    "type": "integer"
                                                },
                                                "invoice_created": {
                                                    "type": "boolean",
                                                    "description": "True when invoice was created from a cart payload."
                                                },
                                                "invoice_id": {
                                                    "type": "string",
                                                    "nullable": true,
                                                    "description": "ID of the newly created invoice (cart payments only)."
                                                },
                                                "is_first_purchase": {
                                                    "type": "boolean",
                                                    "description": "True when this was the account's first completed purchase, captured before this payment's credit_history row is written. Used by the web UI to fire one-off GA4 first_purchase and first_purchase_approved milestone events."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad request or payment failed. PAYMENT_FAILED response is NOT wrapped in the standard envelope; the fields shown here are returned at the top level.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": false
                                        },
                                        "error": {
                                            "type": "string",
                                            "example": "PAYMENT_FAILED"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "invoice_created": {
                                            "type": "boolean"
                                        },
                                        "invoice_id": {
                                            "type": "string",
                                            "nullable": true
                                        },
                                        "invoice_ids": {
                                            "type": "array",
                                            "items": {
                                                "type": "string"
                                            }
                                        },
                                        "total_amount": {
                                            "type": "number"
                                        },
                                        "total_credits": {
                                            "type": "integer"
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "description": "Payment exception. PAYMENT_EXCEPTION response is NOT wrapped in the standard envelope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": false
                                        },
                                        "error": {
                                            "type": "string",
                                            "example": "PAYMENT_EXCEPTION"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "invoice_created": {
                                            "type": "boolean"
                                        },
                                        "invoice_id": {
                                            "type": "string",
                                            "nullable": true
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "oneOf": [
                                    {
                                        "type": "object",
                                        "description": "Pay existing invoices.",
                                        "required": [
                                            "invoice_ids"
                                        ],
                                        "properties": {
                                            "invoice_ids": {
                                                "type": "array",
                                                "items": {
                                                    "type": "string"
                                                },
                                                "minItems": 1,
                                                "example": [
                                                    "S042659",
                                                    "S042660"
                                                ]
                                            }
                                        }
                                    },
                                    {
                                        "type": "object",
                                        "description": "Create invoice from cart and pay.",
                                        "required": [
                                            "cart"
                                        ],
                                        "properties": {
                                            "cart": {
                                                "type": "array",
                                                "items": {
                                                    "type": "object",
                                                    "required": [
                                                        "packageId",
                                                        "quantity"
                                                    ],
                                                    "properties": {
                                                        "packageId": {
                                                            "type": "integer",
                                                            "minimum": 1
                                                        },
                                                        "quantity": {
                                                            "type": "integer",
                                                            "minimum": 1
                                                        }
                                                    }
                                                },
                                                "minItems": 1
                                            },
                                            "discount_code": {
                                                "type": "string",
                                                "nullable": true
                                            }
                                        }
                                    }
                                ]
                            }
                        }
                    }
                }
            }
        },
        "/billing/preauth-payment": {
            "post": {
                "summary": "Pre-authorize credit card payment (Legacy)",
                "deprecated": true,
                "description": "Legacy flow. Submits raw card details for users with ccapproval=0; performs NAB pre-auth + MaxMind fraud check, stores the row in cc, sets affected credit_history rows to status='approval', and emails/SMSs admins. Superseded by /billing/preauth-card which uses NAB Periodic (stored CRN) instead of holding raw card numbers. Authentication: this endpoint accepts only JWT bearer tokens from an interactive login session; API keys (sk_) are not accepted.",
                "tags": [
                    "Billing"
                ],
                "responses": {
                    "200": {
                        "description": "Payment submitted for approval.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message": {
                                                    "type": "string"
                                                },
                                                "payment_id": {
                                                    "type": "integer"
                                                },
                                                "requires_approval": {
                                                    "type": "boolean"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "cc_name",
                                    "cc_number",
                                    "expiry_month",
                                    "expiry_year",
                                    "cc_cvv",
                                    "invoice_data"
                                ],
                                "properties": {
                                    "cc_name": {
                                        "type": "string",
                                        "minLength": 1
                                    },
                                    "cc_number": {
                                        "type": "string",
                                        "pattern": "^[0-9\\s]{13,23}$"
                                    },
                                    "expiry_month": {
                                        "type": "string",
                                        "pattern": "^(0[1-9]|1[0-2])$"
                                    },
                                    "expiry_year": {
                                        "type": "string",
                                        "pattern": "^[0-9]{2}$"
                                    },
                                    "cc_cvv": {
                                        "type": "string",
                                        "pattern": "^[0-9]{3,4}$"
                                    },
                                    "invoice_data": {
                                        "oneOf": [
                                            {
                                                "type": "object",
                                                "description": "Single invoice (nested) - from credit_history page.",
                                                "required": [
                                                    "invoice"
                                                ],
                                                "properties": {
                                                    "invoice": {
                                                        "type": "object",
                                                        "required": [
                                                            "invoice_id",
                                                            "total_with_gst"
                                                        ],
                                                        "properties": {
                                                            "invoice_id": {
                                                                "type": "string"
                                                            },
                                                            "total_with_gst": {
                                                                "type": "number"
                                                            }
                                                        }
                                                    }
                                                }
                                            },
                                            {
                                                "type": "object",
                                                "description": "Single invoice (flat).",
                                                "required": [
                                                    "invoice_id"
                                                ],
                                                "properties": {
                                                    "invoice_id": {
                                                        "type": "string"
                                                    },
                                                    "total_with_gst": {
                                                        "type": "number"
                                                    },
                                                    "total_amount": {
                                                        "type": "number"
                                                    }
                                                }
                                            },
                                            {
                                                "type": "object",
                                                "description": "Multiple invoices (bulk payment).",
                                                "required": [
                                                    "invoices",
                                                    "total_amount"
                                                ],
                                                "properties": {
                                                    "invoices": {
                                                        "type": "array",
                                                        "items": {
                                                            "type": "string"
                                                        },
                                                        "minItems": 1
                                                    },
                                                    "total_amount": {
                                                        "type": "number"
                                                    }
                                                }
                                            }
                                        ]
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                }
            }
        },
        "/blocked_numbers": {
            "get": {
                "summary": "List blocked numbers",
                "description": "Returns a paginated list of blocked numbers for the authenticated user. Subaccounts with `parent_blocks_access` of `view` or `manage` see a merged view of their own blocks and their parent's blocks; if the same number is blocked in both pools, the self-owned row wins. Numbers can be blocked manually (`user`), via inbound SMS STOP (`optout`), or via the web opt-out link (`web_optout`).",
                "tags": [
                    "Blocked Numbers"
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 500,
                            "default": 50
                        },
                        "description": "Items per page (1-500, default 50)."
                    },
                    {
                        "name": "search",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Search query. Accepts one or more comma/whitespace-separated phone numbers (each normalised to E.164, with an `04` -> `614` variant added) and matches `bn.number` with a prefix `LIKE`. If no token parses as a phone number, the value falls back to a substring search of the `notes` column."
                    },
                    {
                        "name": "blocked_by",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "user",
                                "optout",
                                "web_optout"
                            ]
                        },
                        "description": "Filter by how the number was blocked (user=manual, optout=SMS STOP, web_optout=web opt-out link)."
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "created_at",
                                "number",
                                "blocked_by"
                            ],
                            "default": "created_at"
                        },
                        "description": "Field to sort by (default: created_at)."
                    },
                    {
                        "name": "order",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "ASC",
                                "DESC"
                            ],
                            "default": "DESC"
                        },
                        "description": "Sort order (default: DESC). Any value other than `ASC` (case-insensitive) is treated as `DESC`."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Blocked numbers retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Success"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "blocked_numbers": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/BlockedNumber"
                                                    }
                                                },
                                                "pagination": {
                                                    "$ref": "#/components/schemas/Pagination"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            },
            "post": {
                "summary": "Block a number or contact",
                "description": "Adds a phone number to the authenticated user's blocked list (or to the parent pool when `owner=parent` and the caller has `manage` access). Accepts either a `number` or a `contact_id`; when `contact_id` is supplied, the contact's `gsm_number` is used and `notes` defaults to `Blocked via contact`. If the number is already blocked in the target pool, the existing record is returned with the message `Number is already blocked`.",
                "tags": [
                    "Blocked Numbers"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "oneOf": [
                                    {
                                        "type": "object",
                                        "required": [
                                            "number"
                                        ],
                                        "properties": {
                                            "number": {
                                                "type": "string",
                                                "description": "Phone number to block. Validated and normalised to E.164.",
                                                "example": "+61412345678"
                                            },
                                            "notes": {
                                                "type": "string",
                                                "description": "Optional notes about why this number is blocked.",
                                                "example": "Customer requested opt-out"
                                            },
                                            "owner": {
                                                "type": "string",
                                                "enum": [
                                                    "self",
                                                    "parent"
                                                ],
                                                "default": "self",
                                                "description": "Which pool to add this record to. Requires `parent_blocks_access` of `manage` when set to `parent`."
                                            }
                                        }
                                    },
                                    {
                                        "type": "object",
                                        "required": [
                                            "contact_id"
                                        ],
                                        "properties": {
                                            "contact_id": {
                                                "type": "integer",
                                                "description": "Contact ID to block. The contact's `gsm_number` is looked up and used as the blocked number.",
                                                "example": 123
                                            },
                                            "notes": {
                                                "type": "string",
                                                "description": "Optional notes. Defaults to `Blocked via contact` when not supplied.",
                                                "example": "Blocked via contact management"
                                            },
                                            "owner": {
                                                "type": "string",
                                                "enum": [
                                                    "self",
                                                    "parent"
                                                ],
                                                "default": "self",
                                                "description": "Which pool to add this record to. Requires `parent_blocks_access` of `manage` when set to `parent`."
                                            }
                                        }
                                    }
                                ]
                            },
                            "examples": {
                                "byNumber": {
                                    "summary": "Block by phone number",
                                    "value": {
                                        "number": "+61412345678",
                                        "notes": "Customer requested opt-out"
                                    }
                                },
                                "byContact": {
                                    "summary": "Block by contact ID",
                                    "value": {
                                        "contact_id": 123,
                                        "notes": "Blocked via contact management"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Number was already blocked in the target pool; the existing record is returned.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Number is already blocked"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "blocked_number_id": {
                                                    "type": "integer"
                                                },
                                                "number": {
                                                    "type": "string",
                                                    "description": "Normalised E.164 number."
                                                },
                                                "created_at": {
                                                    "type": "string",
                                                    "format": "date-time"
                                                },
                                                "blocked_by": {
                                                    "type": "string",
                                                    "enum": [
                                                        "user",
                                                        "optout",
                                                        "web_optout"
                                                    ]
                                                },
                                                "notes": {
                                                    "type": [
                                                        "string",
                                                        "null"
                                                    ]
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "201": {
                        "description": "Blocked number created. TODO: handler does not return `owner`/`owner_user_id` on this response, unlike the GET endpoints.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Number blocked successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "blocked_number_id": {
                                                    "type": "integer"
                                                },
                                                "number": {
                                                    "type": "string",
                                                    "description": "Normalised E.164 number."
                                                },
                                                "created_at": {
                                                    "type": "string",
                                                    "format": "date-time"
                                                },
                                                "blocked_by": {
                                                    "type": "string",
                                                    "enum": [
                                                        "user"
                                                    ]
                                                },
                                                "notes": {
                                                    "type": [
                                                        "string",
                                                        "null"
                                                    ]
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "description": "Caller lacks permission to add a block in the requested `owner` pool.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/responses/BadRequest"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Contact not found (when using contact_id).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/responses/NotFound"
                                }
                            }
                        }
                    }
                }
            },
            "delete": {
                "summary": "Unblock a contact",
                "description": "Removes any blocked-number rows in the caller's writable pool(s) whose `number` matches the supplied contact's `gsm_number`. Use `DELETE /blocked_numbers/{blocked_number_id}` to delete by row ID instead.",
                "tags": [
                    "Blocked Numbers"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "contact_id"
                                ],
                                "properties": {
                                    "contact_id": {
                                        "type": "integer",
                                        "description": "Contact ID to unblock. The contact's `gsm_number` is looked up and matched against blocked rows.",
                                        "example": 123
                                    }
                                }
                            },
                            "examples": {
                                "unblockContact": {
                                    "summary": "Unblock by contact ID",
                                    "value": {
                                        "contact_id": 123
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Number unblocked successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Success"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message": {
                                                    "type": "string",
                                                    "example": "Blocked number removed successfully"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Contact is not currently blocked or validation error.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/responses/BadRequest"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "Contact not found.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/responses/NotFound"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/blocked_numbers/{blocked_number_id}": {
            "get": {
                "summary": "Get a blocked number",
                "description": "Returns a single blocked number by its ID. The row must belong to a pool readable to the caller (own pool plus parent's pool when `parent_blocks_access` is `view` or `manage`).",
                "tags": [
                    "Blocked Numbers"
                ],
                "parameters": [
                    {
                        "name": "blocked_number_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Blocked number ID."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Blocked number retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Success"
                                        },
                                        "data": {
                                            "$ref": "#/components/schemas/BlockedNumber"
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "delete": {
                "summary": "Unblock a number by ID",
                "description": "Deletes a blocked-number row by ID. The row must belong to a pool writable to the caller (own pool plus parent's pool when `parent_blocks_access` is `manage`).",
                "tags": [
                    "Blocked Numbers"
                ],
                "parameters": [
                    {
                        "name": "blocked_number_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Blocked number ID."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Number unblocked successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Success"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message": {
                                                    "type": "string",
                                                    "example": "Blocked number removed successfully"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/blocked_numbers/bulk": {
            "post": {
                "summary": "Bulk block numbers or contacts",
                "description": "Blocks up to 10,000 numbers in one call. Accepts either a `numbers` array or a `contact_ids` array (if both are supplied, `contact_ids` wins). Each number is validated and normalised to E.164; duplicates already present in the target pool are reported as `already_blocked` and not re-inserted. Honours the same `owner` selector as the single-block endpoint.",
                "tags": [
                    "Blocked Numbers"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "numbers": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        },
                                        "description": "Phone numbers to block. Each is validated and normalised to E.164.",
                                        "maxItems": 10000
                                    },
                                    "contact_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "description": "Contact IDs whose `gsm_number` should be blocked. Takes precedence over `numbers` if both are supplied.",
                                        "maxItems": 10000
                                    },
                                    "notes": {
                                        "type": "string",
                                        "description": "Optional notes stored against every inserted row."
                                    },
                                    "owner": {
                                        "type": "string",
                                        "enum": [
                                            "self",
                                            "parent"
                                        ],
                                        "default": "self",
                                        "description": "Target pool. Requires `parent_blocks_access` of `manage` when `parent`."
                                    }
                                }
                            },
                            "examples": {
                                "byNumbers": {
                                    "summary": "Bulk block by numbers",
                                    "value": {
                                        "numbers": [
                                            "+61412345678",
                                            "+61498765432"
                                        ],
                                        "notes": "Imported from suppression list"
                                    }
                                },
                                "byContacts": {
                                    "summary": "Bulk block by contact IDs",
                                    "value": {
                                        "contact_ids": [
                                            123,
                                            456
                                        ]
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Bulk block summary.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Success"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "blocked": {
                                                    "type": "integer",
                                                    "description": "Count of new rows inserted."
                                                },
                                                "already_blocked": {
                                                    "type": "integer",
                                                    "description": "Count of numbers that were already blocked in the target pool."
                                                },
                                                "invalid": {
                                                    "type": "integer",
                                                    "description": "Count of numbers that failed phone-number validation."
                                                },
                                                "total": {
                                                    "type": "integer",
                                                    "description": "Total numbers processed (resolved from input)."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "description": "Caller lacks permission to write to the requested `owner` pool.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/responses/BadRequest"
                                }
                            }
                        }
                    }
                }
            },
            "delete": {
                "summary": "Bulk unblock numbers or contacts",
                "description": "Unblocks up to 10,000 numbers in one call. Accepts either a `numbers` array or a `contact_ids` array (if both are supplied, `contact_ids` wins). Each number is validated and normalised to E.164; rows are deleted from all pools the caller can write to.",
                "tags": [
                    "Blocked Numbers"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "numbers": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        },
                                        "description": "Phone numbers to unblock.",
                                        "maxItems": 10000
                                    },
                                    "contact_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "description": "Contact IDs whose `gsm_number` should be unblocked. Takes precedence over `numbers` if both are supplied.",
                                        "maxItems": 10000
                                    }
                                }
                            },
                            "examples": {
                                "byNumbers": {
                                    "summary": "Bulk unblock by numbers",
                                    "value": {
                                        "numbers": [
                                            "+61412345678",
                                            "+61498765432"
                                        ]
                                    }
                                },
                                "byContacts": {
                                    "summary": "Bulk unblock by contact IDs",
                                    "value": {
                                        "contact_ids": [
                                            123,
                                            456
                                        ]
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Bulk unblock summary.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Success"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "unblocked": {
                                                    "type": "integer",
                                                    "description": "Count of rows deleted."
                                                },
                                                "not_found": {
                                                    "type": "integer",
                                                    "description": "Count of valid numbers that were not currently blocked."
                                                },
                                                "invalid": {
                                                    "type": "integer",
                                                    "description": "Count of numbers that failed phone-number validation."
                                                },
                                                "total": {
                                                    "type": "integer",
                                                    "description": "Total numbers processed (resolved from input)."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/cards": {
            "get": {
                "summary": "Get stored payment card",
                "description": "Returns the caller's stored payment card (currently max one per user) along with `has_card` and the user's `ccapproval` flag. Requires the `view_billing` permission; subaccounts that draw from parent credits are rejected with 403.",
                "tags": [
                    "Cards"
                ],
                "responses": {
                    "200": {
                        "description": "Card information retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CardsResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                }
            },
            "post": {
                "summary": "Add or replace payment card",
                "description": "Stores a new payment card via the NAB Periodic API and upserts into `nab_periodic`. If a card already exists for the user it is replaced (and any `autotopups.nab_periodic_id` reference is updated). American Express cards are rejected; only Visa/Mastercard (and other detected non-Amex brands) are accepted. Requires the `manage_billing` permission.",
                "tags": [
                    "Cards"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "cc_number",
                                    "cc_expiry",
                                    "cc_name"
                                ],
                                "properties": {
                                    "cc_number": {
                                        "type": "string",
                                        "description": "Full credit card number. Non-digit characters are stripped; must be 13-19 digits.",
                                        "example": "4111111111111111"
                                    },
                                    "cc_expiry": {
                                        "type": "string",
                                        "description": "Card expiry. Accepted in either `MM/YY` or `MMYY` form; must not be in the past.",
                                        "example": "12/25"
                                    },
                                    "cc_name": {
                                        "type": "string",
                                        "description": "Cardholder name as shown on card",
                                        "example": "John Smith"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Card saved successfully. Response message is `Card saved successfully`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CardsResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "NAB Periodic API rejected the card (e.g. declined, invalid). The NAB error message is returned in `message`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "description": "Validation error. Includes missing required fields, invalid card number length, bad/expired `cc_expiry`, or `cc_number` detected as American Express.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ValidationError"
                                }
                            }
                        }
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "put": {
                "summary": "Update card details",
                "description": "Updates the stored card's expiry date and/or cardholder name in the local database only (no NAB call is made). To change the card number, use `POST /cards` to replace the card. Requires the `manage_billing` permission.",
                "tags": [
                    "Cards"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "cc_expiry": {
                                        "type": "string",
                                        "description": "New expiry in `MM/YY` or `MMYY` format; must not be in the past.",
                                        "example": "12/26"
                                    },
                                    "cc_name": {
                                        "type": "string",
                                        "description": "New cardholder name",
                                        "example": "John A. Smith"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Card updated successfully. Response message is `Card updated successfully`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CardsResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "description": "No card on file to update",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Invalid `cc_expiry` format or expiry is in the past.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ValidationError"
                                }
                            }
                        }
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "delete": {
                "summary": "Delete stored card",
                "description": "Removes the stored card from NAB and the local `nab_periodic` table and clears any `autotopups.nab_periodic_id` reference. NAB-side delete failures are logged but do not block local deletion. Requires the `manage_billing` permission.",
                "tags": [
                    "Cards"
                ],
                "responses": {
                    "200": {
                        "description": "Card deleted successfully. Response message is `Card deleted successfully` and `data.cards` is an empty array.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CardsResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "description": "No card on file to delete",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/chats": {
            "get": {
                "summary": "List chat conversations",
                "description": "Returns the list of two-way chat conversations for the caller's account, ordered with starred chats first then by most recent activity. Each row includes a `last_message_preview` (prefixed with `You: ` for outbound, truncated to 50 chars). Blocked chats are excluded; archived chats are hidden unless they are starred.",
                "tags": [
                    "Chats"
                ],
                "security": [
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/Limit"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Chat list retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Chat list loaded"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "chats": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "contact_number": {
                                                                "type": "string",
                                                                "description": "Recipient phone number for the chat."
                                                            },
                                                            "contact_name": {
                                                                "type": "string",
                                                                "nullable": true,
                                                                "description": "Display name from the contacts table, if any."
                                                            },
                                                            "last_sender_id": {
                                                                "type": "string",
                                                                "nullable": true,
                                                                "description": "Sender ID used on the most recent outbound message."
                                                            },
                                                            "last_message_at": {
                                                                "type": "string",
                                                                "format": "date-time",
                                                                "nullable": true,
                                                                "description": "ISO 8601 with offset; null for starred chats with no messages yet."
                                                            },
                                                            "last_message_preview": {
                                                                "type": "string",
                                                                "description": "Up to 50 chars (after the `You: ` prefix on outbound). Empty string when there are no messages."
                                                            },
                                                            "last_message_type": {
                                                                "type": "string",
                                                                "nullable": true,
                                                                "description": "Message type of the last message (e.g. `sms`, `mms`)."
                                                            },
                                                            "is_starred": {
                                                                "type": "boolean"
                                                            },
                                                            "is_blocked": {
                                                                "type": "boolean"
                                                            },
                                                            "is_archived": {
                                                                "type": "boolean",
                                                                "description": "True when the chat has an `archived_at` and the last message is at or before that timestamp."
                                                            },
                                                            "unread_count": {
                                                                "type": "integer"
                                                            }
                                                        }
                                                    }
                                                },
                                                "pagination": {
                                                    "type": "object",
                                                    "properties": {
                                                        "current_page": {
                                                            "type": "integer"
                                                        },
                                                        "total_pages": {
                                                            "type": "integer"
                                                        },
                                                        "total_chats": {
                                                            "type": "integer"
                                                        },
                                                        "per_page": {
                                                            "type": "integer"
                                                        },
                                                        "has_next": {
                                                            "type": "boolean"
                                                        },
                                                        "has_previous": {
                                                            "type": "boolean"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                }
            }
        },
        "/chats/history": {
            "get": {
                "summary": "Get chat message history",
                "description": "Returns the merged outbound/inbound message history for a single contact. Pagination is cursor-based using `before` (older) or `after` (newer) timestamps; the two are mutually exclusive. The handler also accepts this same request at `GET /chats?contact={number}` for legacy callers.",
                "tags": [
                    "Chats"
                ],
                "security": [
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "contact",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "maxLength": 64
                        },
                        "description": "Contact phone number. Variants (digits-only and `+` prefixed) are matched automatically."
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "minimum": 10,
                            "maximum": 200,
                            "default": 100
                        },
                        "description": "Number of messages to retrieve. Values below 10 are clamped to 10; above 200 are clamped to 200."
                    },
                    {
                        "name": "before",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "date-time"
                        },
                        "description": "Load messages strictly older than this timestamp. Mutually exclusive with `after`."
                    },
                    {
                        "name": "after",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "date-time"
                        },
                        "description": "Load messages strictly newer than this timestamp (polling). Mutually exclusive with `before`."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Chat history retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Conversation history loaded"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "contact": {
                                                    "type": "object",
                                                    "properties": {
                                                        "number": {
                                                            "type": "string",
                                                            "description": "The primary normalised contact number."
                                                        },
                                                        "name": {
                                                            "type": "string",
                                                            "description": "Display name; empty string when no contact record exists."
                                                        },
                                                        "contact_id": {
                                                            "type": "integer",
                                                            "nullable": true,
                                                            "description": "Contacts table ID; null when no contact record exists."
                                                        }
                                                    }
                                                },
                                                "messages": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "id": {
                                                                "type": "string",
                                                                "description": "Synthetic identifier (`out_<ref>_<number>` or `in_<ref>`)."
                                                            },
                                                            "ref": {
                                                                "type": "string",
                                                                "description": "Underlying message_ref / incoming_mess_id."
                                                            },
                                                            "direction": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "inbound",
                                                                    "outbound"
                                                                ]
                                                            },
                                                            "body": {
                                                                "type": "string"
                                                            },
                                                            "timestamp": {
                                                                "type": "string",
                                                                "format": "date-time"
                                                            },
                                                            "contact_number": {
                                                                "type": "string",
                                                                "description": "Stripped of all non-alphanumeric/`+`/`_` characters."
                                                            },
                                                            "sender_number": {
                                                                "type": "string",
                                                                "description": "Stripped of all non-alphanumeric/`+`/`_` characters."
                                                            },
                                                            "contact_name": {
                                                                "type": "string",
                                                                "description": "Mirrors `contact.name` for convenience."
                                                            },
                                                            "updated": {
                                                                "type": "string",
                                                                "format": "date-time",
                                                                "description": "Outbound only: when the recipient row was last touched (delivery status update)."
                                                            },
                                                            "delivery_status": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "Pending",
                                                                    "Waiting",
                                                                    "Queued",
                                                                    "Sent",
                                                                    "Delivered",
                                                                    "Read",
                                                                    "Failed",
                                                                    "Blocked",
                                                                    "Invalid",
                                                                    "Unknown"
                                                                ],
                                                                "description": "Outbound only. Collapsed to `Pending`/`Sent` when delivery reports are disabled."
                                                            },
                                                            "slides": {
                                                                "type": "array",
                                                                "description": "MMS slides, present only when the message has any. Generated `animated.gif` slideshows are excluded.",
                                                                "items": {
                                                                    "type": "object",
                                                                    "properties": {
                                                                        "url": {
                                                                            "type": "string"
                                                                        },
                                                                        "size": {
                                                                            "type": "integer",
                                                                            "description": "Slide size in bytes."
                                                                        },
                                                                        "content_type": {
                                                                            "type": "string"
                                                                        },
                                                                        "message_text": {
                                                                            "type": "string",
                                                                            "nullable": true
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                },
                                                "has_more_before": {
                                                    "type": "boolean",
                                                    "description": "True if more messages exist older than the oldest in this page."
                                                },
                                                "has_more_after": {
                                                    "type": "boolean",
                                                    "description": "Always true for now (no terminal-newest signal); use polling with `after`."
                                                },
                                                "oldest_timestamp": {
                                                    "type": "string",
                                                    "format": "date-time",
                                                    "nullable": true
                                                },
                                                "newest_timestamp": {
                                                    "type": "string",
                                                    "format": "date-time",
                                                    "nullable": true
                                                },
                                                "chat": {
                                                    "type": "object",
                                                    "nullable": true,
                                                    "description": "Chat metadata row, or null when no `chats` row exists yet.",
                                                    "properties": {
                                                        "chat_id": {
                                                            "type": "integer"
                                                        },
                                                        "is_starred": {
                                                            "type": "boolean"
                                                        },
                                                        "is_blocked": {
                                                            "type": "boolean"
                                                        },
                                                        "archived_at": {
                                                            "type": "string",
                                                            "format": "date-time",
                                                            "nullable": true,
                                                            "description": "ISO 8601 with timezone offset; null when the chat has never been archived."
                                                        },
                                                        "last_read_at": {
                                                            "type": "string",
                                                            "format": "date-time",
                                                            "nullable": true,
                                                            "description": "ISO 8601 with timezone offset; null when the chat has not been marked read."
                                                        },
                                                        "created_at": {
                                                            "type": "string",
                                                            "format": "date-time",
                                                            "description": "ISO 8601 with timezone offset."
                                                        },
                                                        "updated_at": {
                                                            "type": "string",
                                                            "format": "date-time",
                                                            "description": "ISO 8601 with timezone offset."
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            }
        },
        "/chats/mark-read": {
            "put": {
                "summary": "Mark chat as read",
                "description": "Marks the conversation with `contact` as read up to `timestamp` (defaults to server `now()` when omitted). Resets `unread_count` to 0. Also accepts `POST` and `PATCH`.",
                "tags": [
                    "Chats"
                ],
                "security": [
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "contact",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "maxLength": 64
                        },
                        "description": "Contact phone number."
                    },
                    {
                        "name": "timestamp",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "date-time"
                        },
                        "description": "Mark messages up to this point as read. Defaults to the current server time."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Chat marked as read successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Chat marked as read"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "last_read_at": {
                                                    "type": "string",
                                                    "format": "date-time"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            }
        },
        "/chats/star": {
            "post": {
                "summary": "Star a chat",
                "description": "Pins the conversation with `contact` to the top of the chat list. A user may have at most 3 starred chats at a time. Also accepts `PUT` and `PATCH`.",
                "tags": [
                    "Chats"
                ],
                "security": [
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "contact",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "maxLength": 64
                        },
                        "description": "Contact phone number."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Chat starred successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Chat starred"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "is_starred": {
                                                    "type": "boolean",
                                                    "example": true
                                                },
                                                "is_archived": {
                                                    "type": "boolean"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Star limit reached (max 3) or validation error",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            },
            "delete": {
                "summary": "Unstar a chat",
                "description": "Removes the starred flag from the conversation with `contact`.",
                "tags": [
                    "Chats"
                ],
                "security": [
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "contact",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "maxLength": 64
                        },
                        "description": "Contact phone number."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Chat unstarred successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Chat unstarred"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "is_starred": {
                                                    "type": "boolean",
                                                    "example": false
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            }
        },
        "/chats/archive": {
            "post": {
                "summary": "Archive a chat",
                "description": "Stamps `archived_at` for the conversation with `contact`. The chat is hidden from the default list once its newest message is at or before this timestamp, unless it is starred. Also accepts `PUT` and `PATCH`.",
                "tags": [
                    "Chats"
                ],
                "security": [
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "contact",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "maxLength": 64
                        },
                        "description": "Contact phone number."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Chat archived successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Chat archived"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "is_archived": {
                                                    "type": "boolean"
                                                },
                                                "is_starred": {
                                                    "type": "boolean"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            },
            "delete": {
                "summary": "Unarchive a chat",
                "description": "Clears `archived_at` for the conversation with `contact`, restoring it to the default chat list.",
                "tags": [
                    "Chats"
                ],
                "security": [
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "contact",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "maxLength": 64
                        },
                        "description": "Contact phone number."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Chat unarchived successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Chat unarchived"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "is_archived": {
                                                    "type": "boolean",
                                                    "example": false
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            }
        },
        "/chats/block": {
            "post": {
                "summary": "Block a chat contact",
                "description": "Sets `is_blocked = 1` on the chat row for `contact`, hiding it from the chat list. Note that this only marks the chat row; manage actual block-list entries via the blocked-numbers endpoints. Also accepts `PUT` and `PATCH`.",
                "tags": [
                    "Chats"
                ],
                "security": [
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "contact",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "maxLength": 64
                        },
                        "description": "Contact phone number to block."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Contact blocked successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Chat blocked"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "is_blocked": {
                                                    "type": "boolean",
                                                    "example": true
                                                },
                                                "is_starred": {
                                                    "type": "boolean"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            },
            "delete": {
                "summary": "Unblock a chat contact",
                "description": "Clears `is_blocked` on the chat row for `contact`.",
                "tags": [
                    "Chats"
                ],
                "security": [
                    {
                        "BearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "contact",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "maxLength": 64
                        },
                        "description": "Contact phone number to unblock."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Contact unblocked successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Chat unblocked"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "is_blocked": {
                                                    "type": "boolean",
                                                    "example": false
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            }
        },
        "/config": {
            "get": {
                "summary": "Get client-safe configuration",
                "description": "Returns configuration values intended for the SMS Manager web client. Excludes server-side secrets. Includes a `runtime` object with the server's current time, timezone, and version.",
                "tags": [
                    "Config"
                ],
                "security": [],
                "responses": {
                    "200": {
                        "description": "Configuration retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Configuration retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "sms": {
                                                    "type": "object",
                                                    "additionalProperties": true,
                                                    "description": "SMS-related client config."
                                                },
                                                "mms": {
                                                    "type": "object",
                                                    "additionalProperties": true,
                                                    "description": "MMS-related client config."
                                                },
                                                "ui": {
                                                    "type": "object",
                                                    "additionalProperties": true,
                                                    "description": "UI feature flags and tuning."
                                                },
                                                "scheduling": {
                                                    "type": "object",
                                                    "additionalProperties": true,
                                                    "description": "Scheduling limits and defaults."
                                                },
                                                "validation": {
                                                    "type": "object",
                                                    "additionalProperties": true,
                                                    "description": "Client-side validation rules."
                                                },
                                                "features": {
                                                    "type": "object",
                                                    "additionalProperties": true,
                                                    "description": "Feature flags."
                                                },
                                                "version": {
                                                    "type": "string",
                                                    "example": "2.0.0"
                                                },
                                                "runtime": {
                                                    "type": "object",
                                                    "properties": {
                                                        "timestamp": {
                                                            "type": "integer",
                                                            "description": "Server Unix epoch seconds."
                                                        },
                                                        "timezone": {
                                                            "type": "string",
                                                            "example": "Australia/Melbourne"
                                                        },
                                                        "version": {
                                                            "type": "string",
                                                            "example": "2.0.0"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/contact-fields": {
            "get": {
                "summary": "List custom contact fields",
                "description": "Returns the authenticated user's custom contact fields, merged across the self pool and (for subaccounts with parent contact access) the parent pool. When both pools define a field with the same name, the self-owned definition wins. Each item includes a `contact_count` showing how many contacts in that pool currently have a stored value for the field.",
                "tags": [
                    "Contacts"
                ],
                "responses": {
                    "200": {
                        "description": "Custom contact fields retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "fields": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "field_id": {
                                                                "type": "integer"
                                                            },
                                                            "display_name": {
                                                                "type": "string",
                                                                "description": "Display name of the custom field."
                                                            },
                                                            "owner": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "self",
                                                                    "parent"
                                                                ],
                                                                "description": "Which pool this field belongs to relative to the caller."
                                                            },
                                                            "owner_user_id": {
                                                                "type": "integer",
                                                                "description": "User id that owns the field row."
                                                            },
                                                            "contact_count": {
                                                                "type": "integer",
                                                                "description": "Number of contacts in the owner pool that currently have a stored value for this field."
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "post": {
                "summary": "Create a custom contact field",
                "description": "Creates a new custom contact field for the caller. The name must be 1-60 characters and unique (case-insensitive) within the target owner pool. Subaccounts with `parent_contact_access` of `manage` may pass `owner: parent` to create the field in the parent pool.",
                "tags": [
                    "Contacts"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "field_name"
                                ],
                                "properties": {
                                    "field_name": {
                                        "type": "string",
                                        "maxLength": 60,
                                        "description": "Display name for the new custom field. Must be unique per owner pool (case-insensitive)."
                                    },
                                    "owner": {
                                        "type": "string",
                                        "enum": [
                                            "self",
                                            "parent"
                                        ],
                                        "default": "self",
                                        "description": "Which pool to add this record to. Requires `parent_contact_access` of `manage` when set to `parent`."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Custom field created.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Custom field created"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "field_id": {
                                                    "type": "integer"
                                                },
                                                "display_name": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/ValidationError"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/contact-fields/{field_id}": {
            "put": {
                "summary": "Rename a custom contact field",
                "description": "Renames an existing custom contact field. The caller must have write access to the field's owner pool. The new name must be 1-60 characters and unique (case-insensitive) within that pool.",
                "tags": [
                    "Contacts"
                ],
                "parameters": [
                    {
                        "name": "field_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "field_name"
                                ],
                                "properties": {
                                    "field_name": {
                                        "type": "string",
                                        "maxLength": 60
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Custom field updated.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Custom field updated"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "field_id": {
                                                    "type": "integer"
                                                },
                                                "display_name": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/ValidationError"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "patch": {
                "summary": "Rename a custom contact field",
                "description": "Alias for `PUT /contact-fields/{field_id}`. Renames an existing custom contact field. The caller must have write access to the field's owner pool.",
                "tags": [
                    "Contacts"
                ],
                "parameters": [
                    {
                        "name": "field_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "field_name"
                                ],
                                "properties": {
                                    "field_name": {
                                        "type": "string",
                                        "maxLength": 60
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Custom field updated.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Custom field updated"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "field_id": {
                                                    "type": "integer"
                                                },
                                                "display_name": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/ValidationError"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "delete": {
                "summary": "Delete a custom contact field",
                "description": "Deletes a custom contact field and removes all stored values for that field from every contact. The caller must have write access to the field's owner pool. Returns the number of contact values that were removed.",
                "tags": [
                    "Contacts"
                ],
                "parameters": [
                    {
                        "name": "field_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Custom field deleted.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Custom field deleted"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "field_id": {
                                                    "type": "integer"
                                                },
                                                "removed_values": {
                                                    "type": "integer",
                                                    "description": "Number of `contact_fields_values` rows that were deleted."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/contacts": {
            "get": {
                "summary": "List contacts",
                "description": "Get a paginated list of contacts visible to the caller (own pool plus, for subaccounts with `parent_contact_access` of `view`/`manage`, the merged parent pool with the clone-replaces-parent priority rule applied). Each contact includes block-status flags and group/custom-field details.\n\nPass `format=ids_only` to skip pagination and return just `{ids: [...], total: N}` for the matching set — used by bulk-action UIs that only need contact IDs.",
                "tags": [
                    "Contacts"
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/Limit"
                    },
                    {
                        "$ref": "#/components/parameters/Search"
                    },
                    {
                        "name": "group_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Filter by group ID. Parent-owned groups also pull in the caller's self-owned clones that shadow a parent member of the group via matching `gsm_number`."
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "display_name",
                                "gsm_number",
                                "email"
                            ],
                            "default": "display_name"
                        },
                        "description": "Field to sort by. Invalid values fall back to `display_name`. Ignored when `format=ids_only`."
                    },
                    {
                        "name": "direction",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "asc",
                                "desc"
                            ],
                            "default": "asc"
                        },
                        "description": "Sort direction. Anything other than `desc` (case-insensitive) is treated as `asc`. Ignored when `format=ids_only`."
                    },
                    {
                        "name": "format",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "ids_only"
                            ]
                        },
                        "description": "When set to `ids_only`, returns only matching contact IDs (no pagination, no per-contact group/custom-field lookups). Response data shape becomes `{ids: integer[], total: integer}`."
                    },
                    {
                        "name": "owner",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "self",
                                "parent"
                            ],
                            "default": "all"
                        },
                        "description": "Filter by ownership when the calling user is a subaccount with `parent_contact_access` of `view` or `manage`. `self` returns only the subaccount's own contacts; `parent` returns only the parent's (with self-owned clones substituting for shadowed originals); `all` (default) returns the merged list with the priority rule applied. Silently downgrades to `all` when the requested pool isn't readable for this user."
                    },
                    {
                        "name": "ungrouped",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "1"
                            ]
                        },
                        "description": "When `1`, returns only contacts with zero group memberships. Mutually exclusive with `group_id` (the latter wins if both are set). The response always includes a filter-agnostic `count_ungrouped` total alongside `count_by_owner`."
                    },
                    {
                        "name": "blocked",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "blocked",
                                "not_blocked"
                            ]
                        },
                        "description": "Filter by block status against the union of every block list the caller can see (own pool plus parent's where access allows). `blocked` returns only contacts whose `gsm_number` appears in a visible block list; `not_blocked` returns only those that do not."
                    },
                    {
                        "name": "active_status",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "active",
                                "inactive"
                            ]
                        },
                        "description": "Filter by group-membership active flag. Requires `group_id` to also be supplied — ignored otherwise. `active` matches `contacts_to_groups.active = 1`; `inactive` matches `= 0`."
                    },
                    {
                        "name": "group_ids",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Comma-separated group IDs. Returns contacts belonging to ANY listed group (de-duplicated). Ignored when group_id is supplied."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Contacts retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Contacts retrieved successfully"
                                        },
                                        "data": {
                                            "oneOf": [
                                                {
                                                    "type": "object",
                                                    "description": "Default paginated shape.",
                                                    "properties": {
                                                        "contacts": {
                                                            "type": "array",
                                                            "items": {
                                                                "type": "object",
                                                                "properties": {
                                                                    "id": {
                                                                        "type": "integer"
                                                                    },
                                                                    "display_name": {
                                                                        "type": "string",
                                                                        "nullable": true
                                                                    },
                                                                    "gsm_number": {
                                                                        "type": "string"
                                                                    },
                                                                    "email": {
                                                                        "type": "string",
                                                                        "nullable": true
                                                                    },
                                                                    "description": {
                                                                        "type": "string",
                                                                        "nullable": true
                                                                    },
                                                                    "is_blocked": {
                                                                        "type": "boolean",
                                                                        "description": "True if the number appears in any block list the caller can see (own + parent's where access allows)."
                                                                    },
                                                                    "blocked_by_self": {
                                                                        "type": "boolean",
                                                                        "description": "True if the number is blocked in the caller's own pool."
                                                                    },
                                                                    "blocked_by_parent": {
                                                                        "type": "boolean",
                                                                        "description": "True if the number is blocked in the parent's pool (and the parent's blocks are visible to the caller)."
                                                                    },
                                                                    "owner": {
                                                                        "type": "string",
                                                                        "enum": [
                                                                            "self",
                                                                            "parent"
                                                                        ],
                                                                        "description": "Which pool this contact belongs to relative to the caller."
                                                                    },
                                                                    "owner_user_id": {
                                                                        "type": "integer",
                                                                        "description": "user_id that owns this contact row."
                                                                    },
                                                                    "groups": {
                                                                        "type": "array",
                                                                        "items": {
                                                                            "type": "object",
                                                                            "properties": {
                                                                                "id": {
                                                                                    "type": "integer"
                                                                                },
                                                                                "name": {
                                                                                    "type": "string"
                                                                                },
                                                                                "is_active": {
                                                                                    "type": "boolean",
                                                                                    "description": "Reflects `contacts_to_groups.active`. NULL is treated as active."
                                                                                }
                                                                            }
                                                                        }
                                                                    },
                                                                    "custom_fields": {
                                                                        "type": "array",
                                                                        "items": {
                                                                            "type": "object",
                                                                            "properties": {
                                                                                "id": {
                                                                                    "type": "integer"
                                                                                },
                                                                                "name": {
                                                                                    "type": "string"
                                                                                },
                                                                                "value": {
                                                                                    "type": "string"
                                                                                }
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        },
                                                        "pagination": {
                                                            "type": "object",
                                                            "description": "Custom paged shape used by this endpoint (not the {total, limit, offset, has_more} variant).",
                                                            "properties": {
                                                                "current_page": {
                                                                    "type": "integer"
                                                                },
                                                                "per_page": {
                                                                    "type": "integer"
                                                                },
                                                                "total": {
                                                                    "type": "integer"
                                                                },
                                                                "total_pages": {
                                                                    "type": "integer"
                                                                }
                                                            }
                                                        },
                                                        "count_by_owner": {
                                                            "type": "object",
                                                            "description": "Filter-agnostic per-owner totals used to drive the All/Mine/Parent's pseudo-groups. Omitted when no readable pool exists.",
                                                            "properties": {
                                                                "self": {
                                                                    "type": "integer",
                                                                    "description": "Every self-owned contact (clones included)."
                                                                },
                                                                "parent": {
                                                                    "type": "integer",
                                                                    "description": "Every parent-owned contact (raw — each parent appears in the parent's view exactly once)."
                                                                },
                                                                "all": {
                                                                    "type": "integer",
                                                                    "description": "self + parents that are NOT shadowed by a clone."
                                                                }
                                                            }
                                                        },
                                                        "count_ungrouped": {
                                                            "type": "integer",
                                                            "description": "Filter-agnostic count of readable contacts with zero group memberships (priority rule applied)."
                                                        }
                                                    }
                                                },
                                                {
                                                    "type": "object",
                                                    "description": "Shape returned when `format=ids_only`.",
                                                    "properties": {
                                                        "ids": {
                                                            "type": "array",
                                                            "items": {
                                                                "type": "integer"
                                                            }
                                                        },
                                                        "total": {
                                                            "type": "integer"
                                                        }
                                                    }
                                                }
                                            ]
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            },
            "post": {
                "summary": "Create contact",
                "description": "Creates a new contact in the caller's own pool (or in the parent pool when `owner=parent` and `parent_contact_access` is `manage`). The `gsm_number` is normalised via libphonenumber before insertion. Group IDs and explicit custom-field IDs must belong to the resolved target owner.",
                "tags": [
                    "Contacts"
                ],
                "responses": {
                    "201": {
                        "description": "Contact created.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Contact created successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "integer",
                                                    "description": "Newly created contact ID."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "description": "Caller lacks `manage` access to the requested parent pool."
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "gsm_number"
                                ],
                                "properties": {
                                    "display_name": {
                                        "type": "string"
                                    },
                                    "gsm_number": {
                                        "type": "string",
                                        "description": "Phone number; normalised to E.164 via libphonenumber before storage."
                                    },
                                    "email": {
                                        "type": "string",
                                        "format": "email"
                                    },
                                    "description": {
                                        "type": "string"
                                    },
                                    "group_ids": {
                                        "type": "array",
                                        "description": "Group IDs to assign this contact to. Every supplied ID must be owned by the target user (self or, when `owner=parent`, the parent). A mismatch returns 400; IDs not owned at all are silently dropped from the final membership set.",
                                        "items": {
                                            "type": "integer",
                                            "minimum": 1
                                        }
                                    },
                                    "custom_fields": {
                                        "type": "array",
                                        "items": {
                                            "type": "object",
                                            "required": [
                                                "value"
                                            ],
                                            "properties": {
                                                "id": {
                                                    "type": "integer",
                                                    "description": "Field ID (use this OR name). Must belong to the target owner pool."
                                                },
                                                "name": {
                                                    "type": "string",
                                                    "description": "Field name (use this OR id). Looked up in the target owner pool."
                                                },
                                                "value": {
                                                    "type": "string",
                                                    "description": "Field value. Empty/whitespace values are silently skipped."
                                                }
                                            }
                                        },
                                        "description": "Custom field values - provide either id or name for each field."
                                    },
                                    "owner": {
                                        "type": "string",
                                        "enum": [
                                            "self",
                                            "parent"
                                        ],
                                        "default": "self",
                                        "description": "Which pool to add this record to. Requires `parent_contact_access` of `manage` when set to `parent`."
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/contacts/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Contact ID"
                }
            ],
            "get": {
                "summary": "Get contact",
                "description": "Fetches a single contact, including its groups and custom-field values. Lookup is scoped to the readable pool (own + parent's where access allows). Returns 404 when the contact is outside that pool.",
                "tags": [
                    "Contacts"
                ],
                "responses": {
                    "200": {
                        "description": "Contact retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Contact retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "integer"
                                                },
                                                "display_name": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "gsm_number": {
                                                    "type": "string"
                                                },
                                                "email": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "description": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "owner": {
                                                    "type": "string",
                                                    "enum": [
                                                        "self",
                                                        "parent"
                                                    ]
                                                },
                                                "owner_user_id": {
                                                    "type": "integer"
                                                },
                                                "groups": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "id": {
                                                                "type": "integer"
                                                            },
                                                            "group_id": {
                                                                "type": "integer",
                                                                "description": "Duplicate of `id` (kept for backward compatibility)."
                                                            },
                                                            "name": {
                                                                "type": "string"
                                                            },
                                                            "is_active": {
                                                                "type": "boolean"
                                                            }
                                                        }
                                                    }
                                                },
                                                "custom_fields": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "id": {
                                                                "type": "integer"
                                                            },
                                                            "name": {
                                                                "type": "string"
                                                            },
                                                            "value": {
                                                                "type": "string"
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "put": {
                "summary": "Update contact",
                "description": "Updates the supplied fields on a contact. Scoped to the writable pool (own + parent's when `parent_contact_access` is `manage`). Group memberships passed in replace the existing set (preserving active-flag state for already-present groups); custom field values are fully replaced (existing rows deleted, then re-inserted). Also accepts PATCH.",
                "tags": [
                    "Contacts"
                ],
                "responses": {
                    "200": {
                        "description": "Contact updated.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Contact updated successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "nullable": true,
                                            "description": "Null on success."
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                },
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "display_name": {
                                        "type": "string"
                                    },
                                    "gsm_number": {
                                        "type": "string",
                                        "description": "When supplied, normalised to E.164 via libphonenumber before storage."
                                    },
                                    "email": {
                                        "type": "string",
                                        "format": "email"
                                    },
                                    "description": {
                                        "type": "string"
                                    },
                                    "group_ids": {
                                        "type": "array",
                                        "description": "Replaces the current group membership set. Every supplied ID must belong to the contact's owner pool (mismatch returns 400); IDs not owned at all are silently dropped. Existing memberships that remain selected keep their active flag; new ones default to active=1.",
                                        "items": {
                                            "type": "integer",
                                            "minimum": 1
                                        }
                                    },
                                    "custom_fields": {
                                        "type": "array",
                                        "items": {
                                            "type": "object",
                                            "required": [
                                                "value"
                                            ],
                                            "properties": {
                                                "id": {
                                                    "type": "integer",
                                                    "description": "Field ID (use this OR name). Must belong to the contact's owner pool — mismatch returns 400."
                                                },
                                                "name": {
                                                    "type": "string",
                                                    "description": "Field name (use this OR id). Looked up in the contact's owner pool."
                                                },
                                                "value": {
                                                    "type": "string",
                                                    "description": "Field value. Empty/whitespace values are silently skipped."
                                                }
                                            }
                                        },
                                        "description": "When provided, replaces all existing custom field values for this contact."
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                }
            },
            "delete": {
                "summary": "Delete contact",
                "description": "Deletes a contact. Scoped to the writable pool (own + parent's when `parent_contact_access` is `manage`). Child rows in `contacts_to_groups` and `contact_fields_values` are NOT cascaded — MyISAM has no foreign keys and the single-row delete intentionally preserves legacy behaviour. Use `/contacts/bulk-delete` for cascading cleanup.",
                "tags": [
                    "Contacts"
                ],
                "responses": {
                    "200": {
                        "description": "Contact deleted.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Contact deleted successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "nullable": true,
                                            "description": "Null on success."
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/contacts/export": {
            "get": {
                "summary": "Export contacts",
                "description": "Streams a CSV, XLSX or JSON file containing every contact in the readable pool (priority rule applied for parent-shadowed rows). Optionally filters by group. The response is the file itself, not the standard JSON envelope.",
                "tags": [
                    "Contacts"
                ],
                "parameters": [
                    {
                        "name": "format",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "csv",
                                "excel",
                                "json"
                            ],
                            "default": "csv"
                        },
                        "description": "Export format."
                    },
                    {
                        "name": "include_groups",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "true",
                                "false"
                            ]
                        },
                        "description": "Pass the literal string `true` to include a `Groups` column (semicolon-joined group names). Any other value is treated as false."
                    },
                    {
                        "name": "include_custom_fields",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "true",
                                "false"
                            ]
                        },
                        "description": "Pass the literal string `true` to include one column per custom field name encountered. Any other value is treated as false."
                    },
                    {
                        "name": "group_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Only export contacts in this group. Mirrors the listing endpoint's parent-group shadow-clone behaviour. When set, the group name is appended to the download filename."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Contact export. The response body is the export file, served as an attachment.",
                        "content": {
                            "text/csv": [],
                            "application/json": [],
                            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": []
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "No contacts found to export."
                    }
                }
            }
        },
        "/contacts/{id}/clone": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Source contact ID (must be owned by the calling user's parent account)"
                }
            ],
            "post": {
                "summary": "Clone a parent-owned contact into your own pool",
                "description": "Creates a copy of the specified parent contact in the calling user's own pool. Custom fields used by the source contact are auto-cloned by name into the caller's pool if missing (existing same-name fields are reused, even if their `field_type` differs). Group memberships are NOT copied. Requires `parent_contact_access` of `view` or `manage`. Wrapped in a transaction.",
                "tags": [
                    "Contacts"
                ],
                "responses": {
                    "200": {
                        "description": "Cloned successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "contact_id": {
                                                    "type": "integer",
                                                    "description": "Identifier of the newly cloned contact in the caller's own pool"
                                                },
                                                "auto_cloned_fields": {
                                                    "type": "array",
                                                    "description": "Names of any custom fields that were auto-cloned into the caller's pool to support this contact",
                                                    "items": {
                                                        "type": "string"
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Invalid contact id."
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "description": "No parent contact access (calling user is not a subaccount, or `parent_contact_access` is `none`)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Source contact not found in parent pool",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "Clone transaction failed; rolled back."
                    }
                }
            }
        },
        "/contacts/bulk-delete": {
            "post": {
                "summary": "Bulk delete contacts",
                "description": "Deletes multiple contacts in chunks of 1000, cascading deletes through `contact_fields_values` and `contacts_to_groups`. Scoped to the writable pool (own + parent's when `parent_contact_access` is `manage`). Returns success with per-row error info when at least one row deleted; returns 400 with the same payload when nothing was deleted.",
                "tags": [
                    "Contacts"
                ],
                "responses": {
                    "200": {
                        "description": "At least one contact was deleted.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Successfully deleted 3 contacts"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "deleted": {
                                                    "type": "integer",
                                                    "description": "Number of contact rows actually removed."
                                                },
                                                "requested": {
                                                    "type": "integer",
                                                    "description": "Number of unique numeric IDs after dedupe/filter."
                                                },
                                                "errors": {
                                                    "type": "array",
                                                    "description": "Human-readable error messages (e.g. count of IDs not found or not owned).",
                                                    "items": {
                                                        "type": "string"
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad input (missing/invalid `contact_ids`) OR nothing was deleted. In the latter case the body still contains `deleted`/`requested`/`errors` under `data`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "contact_ids"
                                ],
                                "properties": {
                                    "contact_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer",
                                            "minimum": 1
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/discounts/validate-promo": {
            "post": {
                "summary": "Validate promotional code",
                "description": "Validates a promotional code (type `P`) used during top-up. Returns the credit value attached to the code. Requires authentication.",
                "tags": [
                    "Discounts"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "code"
                                ],
                                "properties": {
                                    "code": {
                                        "type": "string",
                                        "description": "Promotional code. Case-insensitive."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Promotional code is valid.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Valid promotional code"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "valid": {
                                                    "type": "boolean",
                                                    "example": true
                                                },
                                                "credits": {
                                                    "type": "integer",
                                                    "description": "Number of bonus credits granted by this promotional code."
                                                },
                                                "description": {
                                                    "type": "string",
                                                    "description": "Human-readable description of the promotion."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            }
        },
        "/discounts/validate-discount": {
            "post": {
                "summary": "Validate discount code",
                "description": "Validates an authenticated discount code (type `D`) and returns the percentage discount it represents.",
                "tags": [
                    "Discounts"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "code"
                                ],
                                "properties": {
                                    "code": {
                                        "type": "string",
                                        "description": "Discount code. Case-insensitive."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Discount code is valid for this user.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Valid discount code"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "valid": {
                                                    "type": "boolean",
                                                    "example": true
                                                },
                                                "percentage": {
                                                    "type": "integer",
                                                    "description": "Discount percentage applied to the purchase (sourced from `discounts_promotions.icredits`)."
                                                },
                                                "description": {
                                                    "type": "string",
                                                    "description": "Human-readable description of the discount."
                                                },
                                                "first_purchase_only": {
                                                    "type": "boolean",
                                                    "description": "True if the discount may only be used when the user has no prior purchase."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            }
        },
        "/feedback": {
            "post": {
                "summary": "Submit feedback",
                "description": "Submits user feedback that is emailed to the support team. The authenticated user's name and email are looked up from the database and included in the message.",
                "tags": [
                    "Feedback"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "type",
                                    "message"
                                ],
                                "properties": {
                                    "type": {
                                        "type": "string",
                                        "enum": [
                                            "bug",
                                            "feature",
                                            "improvement",
                                            "question",
                                            "other"
                                        ],
                                        "description": "Type of feedback"
                                    },
                                    "message": {
                                        "type": "string",
                                        "maxLength": 2000,
                                        "description": "Feedback message content (max 2000 characters)"
                                    },
                                    "url": {
                                        "type": "string",
                                        "description": "URL of the page where feedback was submitted. Defaults to 'N/A' when omitted."
                                    },
                                    "userAgent": {
                                        "type": "string",
                                        "description": "Browser user agent string. Defaults to 'N/A' when omitted."
                                    }
                                }
                            },
                            "example": {
                                "type": "feature",
                                "message": "It would be great to have bulk export functionality for contacts.",
                                "url": "/v2/contacts",
                                "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Feedback submitted successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Success"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message": {
                                                    "type": "string",
                                                    "example": "Feedback submitted successfully"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "405": {
                        "description": "Method not allowed (only POST is supported)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    },
                    "500": {
                        "$ref": "#/components/responses/ServerError"
                    }
                }
            }
        },
        "/groups": {
            "get": {
                "summary": "List groups",
                "description": "Returns groups visible to the caller across their own pool and (for subaccounts with parent contact access) the parent pool. Parent groups whose name collides with a self group of the same name are suppressed in favour of the self group.",
                "tags": [
                    "Groups"
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/Limit"
                    },
                    {
                        "$ref": "#/components/parameters/Search"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Groups retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Groups retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "groups": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "id": {
                                                                "type": "integer"
                                                            },
                                                            "name": {
                                                                "type": "string"
                                                            },
                                                            "description": {
                                                                "type": "string",
                                                                "nullable": true
                                                            },
                                                            "optout_immune": {
                                                                "type": "boolean",
                                                                "description": "When true, members are exempt from opt-out deactivation: an opt-out does not remove them from this group (they are still added to the block list)."
                                                            },
                                                            "owner": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "self",
                                                                    "parent"
                                                                ],
                                                                "description": "Which pool owns this group relative to the caller."
                                                            },
                                                            "owner_user_id": {
                                                                "type": "integer"
                                                            },
                                                            "contact_count": {
                                                                "type": "integer",
                                                                "description": "Active members owned by the same pool as the group."
                                                            },
                                                            "inactive_contact_count": {
                                                                "type": "integer",
                                                                "description": "Members of the group with active = 0."
                                                            }
                                                        }
                                                    }
                                                },
                                                "contact_count": {
                                                    "type": "integer",
                                                    "description": "Total contacts in the caller's own pool (ungrouped + grouped)."
                                                },
                                                "pagination": {
                                                    "type": "object",
                                                    "properties": {
                                                        "current_page": {
                                                            "type": "integer"
                                                        },
                                                        "per_page": {
                                                            "type": "integer"
                                                        },
                                                        "total": {
                                                            "type": "integer"
                                                        },
                                                        "total_pages": {
                                                            "type": "integer"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            },
            "post": {
                "summary": "Create group",
                "description": "Creates a new group in either the caller's own pool or the parent's pool. Pool-isolation: any initial members supplied via `contact_ids` must belong to the target pool. Requires `manage_contacts` permission; using `owner: parent` additionally requires `parent_contact_access` of `manage`.",
                "tags": [
                    "Groups"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "maxLength": 40
                                    },
                                    "description": {
                                        "type": "string",
                                        "maxLength": 125
                                    },
                                    "optout_immune": {
                                        "type": "boolean",
                                        "default": false,
                                        "description": "When true, members are exempt from opt-out deactivation: an opt-out does not remove them from this group (they are still added to the block list). Use sparingly, for non-marketing/transactional groups only."
                                    },
                                    "owner": {
                                        "type": "string",
                                        "enum": [
                                            "self",
                                            "parent"
                                        ],
                                        "default": "self",
                                        "description": "Which pool to add this record to. Requires `parent_contact_access` of `manage` when set to `parent`."
                                    },
                                    "contact_ids": {
                                        "type": "array",
                                        "description": "Optional list of contact IDs to add to the new group as initial members. All contacts must belong to the same pool as the group's owner.",
                                        "items": {
                                            "type": "integer",
                                            "minimum": 1
                                        }
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Group created successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Group created successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "integer",
                                                    "description": "ID of the newly created group."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "description": "Caller lacks permission to create a group in the requested pool.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            },
            "delete": {
                "summary": "Delete multiple groups",
                "description": "Deletes several groups at once from the writable pool. Group members are either moved into a single target group (default) or, when `contact_action` is `delete`, any contact left with no remaining groups **across the whole deletion set** is also deleted (a contact in two deleted groups is removed only after both are gone). The target group must belong to the caller's writable pool and must not be one of the groups being deleted.",
                "tags": [
                    "Groups"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "group_ids"
                                ],
                                "properties": {
                                    "group_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer",
                                            "minimum": 1
                                        },
                                        "minItems": 1,
                                        "description": "IDs of the groups to delete."
                                    },
                                    "contact_action": {
                                        "type": "string",
                                        "enum": [
                                            "move",
                                            "delete"
                                        ],
                                        "default": "move",
                                        "description": "What to do with contacts in the deleted groups: 'move' all of them into target_group_id, or 'delete' those left with no remaining group across the set."
                                    },
                                    "target_group_id": {
                                        "type": "integer",
                                        "minimum": 1,
                                        "description": "Target group to receive contacts (required when contact_action is 'move'). Must be in the writable pool and not one of group_ids."
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Groups deleted successfully. `data` contains `deleted_groups` and `affected_contacts`; the `message` reports how many contacts were moved or deleted.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Group 'Customers' deleted successfully. 12 contacts moved to target group"
                                        },
                                        "data": {
                                            "type": "object",
                                            "nullable": true,
                                            "example": null
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            }
        },
        "/groups/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Group ID"
                }
            ],
            "get": {
                "summary": "Get group",
                "description": "Returns a single group's metadata along with its full active member list (no pagination). Members are listed strictly from the group owner's pool. Only contacts with a non-empty `gsm_number` are included.",
                "tags": [
                    "Groups"
                ],
                "responses": {
                    "200": {
                        "description": "Group retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Group retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "integer"
                                                },
                                                "name": {
                                                    "type": "string"
                                                },
                                                "description": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "optout_immune": {
                                                    "type": "boolean",
                                                    "description": "When true, members are exempt from opt-out deactivation (they are still added to the block list)."
                                                },
                                                "owner": {
                                                    "type": "string",
                                                    "enum": [
                                                        "self",
                                                        "parent"
                                                    ]
                                                },
                                                "owner_user_id": {
                                                    "type": "integer"
                                                },
                                                "contact_count": {
                                                    "type": "integer"
                                                },
                                                "inactive_contact_count": {
                                                    "type": "integer"
                                                },
                                                "mobile_numbers": {
                                                    "type": "array",
                                                    "description": "Convenience list of every active member's `gsm_number`.",
                                                    "items": {
                                                        "type": "string"
                                                    }
                                                },
                                                "contacts": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "id": {
                                                                "type": "integer"
                                                            },
                                                            "name": {
                                                                "type": "string"
                                                            },
                                                            "gsm_number": {
                                                                "type": "string"
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "put": {
                "summary": "Update group",
                "description": "Updates a group's name and/or description in the writable pool (self always, parent if `parent_contact_access` is `manage`). Accepts either `name` or `group_name` for the title field. NOTE: response keys here are `group_id` and `group_name` rather than the `id`/`name` shape used by list/get responses.",
                "tags": [
                    "Groups"
                ],
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "maxLength": 40,
                                        "description": "Group name"
                                    },
                                    "group_name": {
                                        "type": "string",
                                        "maxLength": 40,
                                        "description": "Alternative to 'name' for backward compatibility. If both provided, `group_name` wins."
                                    },
                                    "description": {
                                        "type": "string",
                                        "maxLength": 125,
                                        "description": "Group description"
                                    },
                                    "optout_immune": {
                                        "type": "boolean",
                                        "description": "When true, members are exempt from opt-out deactivation: an opt-out does not remove them from this group (they are still added to the block list). Use sparingly, for non-marketing/transactional groups only."
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Group updated successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Group updated successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "nullable": true,
                                            "description": "Null if the refetch step failed; otherwise the updated group.",
                                            "properties": {
                                                "group_id": {
                                                    "type": "integer"
                                                },
                                                "group_name": {
                                                    "type": "string"
                                                },
                                                "description": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "optout_immune": {
                                                    "type": "boolean",
                                                    "description": "When true, members are exempt from opt-out deactivation (they are still added to the block list)."
                                                },
                                                "contact_count": {
                                                    "type": "integer"
                                                },
                                                "inactive_contact_count": {
                                                    "type": "integer"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            },
            "delete": {
                "summary": "Delete group",
                "description": "Deletes a group from the writable pool. Group members are either moved into a target group (default) or, when `contact_action` is `delete`, any contact left with no remaining groups is also deleted. The target group, when supplied, must belong to the same pool as the group being deleted.",
                "tags": [
                    "Groups"
                ],
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "contact_action": {
                                        "type": "string",
                                        "enum": [
                                            "move",
                                            "delete"
                                        ],
                                        "default": "move",
                                        "description": "What to do with contacts in the group: 'move' to another group or 'delete' those left with no remaining groups."
                                    },
                                    "target_group_id": {
                                        "type": "integer",
                                        "minimum": 1,
                                        "description": "Target group ID to receive contacts (required when contact_action is 'move'). Must belong to the same pool as the group being deleted."
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Group deleted successfully. The `data` field is null; the human-readable `message` reports how many contacts were moved or deleted.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Group 'Customers' deleted successfully. 12 contacts moved to target group"
                                        },
                                        "data": {
                                            "type": "object",
                                            "nullable": true,
                                            "example": null
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            }
        },
        "/groups/{id}/contacts": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Group ID"
                }
            ],
            "get": {
                "summary": "List group contacts",
                "description": "Returns a paginated list of every contact in the group (both active and inactive memberships) restricted to the group owner's pool.",
                "tags": [
                    "Groups"
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/Limit"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Group contacts retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Group contacts retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "contacts": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "id": {
                                                                "type": "integer"
                                                            },
                                                            "display_name": {
                                                                "type": "string"
                                                            },
                                                            "gsm_number": {
                                                                "type": "string",
                                                                "nullable": true
                                                            },
                                                            "email": {
                                                                "type": "string",
                                                                "nullable": true
                                                            },
                                                            "description": {
                                                                "type": "string",
                                                                "nullable": true
                                                            },
                                                            "owner": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "self",
                                                                    "parent"
                                                                ]
                                                            },
                                                            "owner_user_id": {
                                                                "type": "integer"
                                                            }
                                                        }
                                                    }
                                                },
                                                "pagination": {
                                                    "type": "object",
                                                    "properties": {
                                                        "current_page": {
                                                            "type": "integer"
                                                        },
                                                        "per_page": {
                                                            "type": "integer"
                                                        },
                                                        "total": {
                                                            "type": "integer"
                                                        },
                                                        "total_pages": {
                                                            "type": "integer"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "post": {
                "summary": "Add contacts to group",
                "description": "Adds one or more contacts to the group. Each supplied `contact_id` is categorised as added, already in group, skipped (cross-pool: contact lives in a different pool than the group), or not found. The response surfaces all four counts so the UI can explain partial successes.",
                "tags": [
                    "Groups"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "contact_ids"
                                ],
                                "properties": {
                                    "contact_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer",
                                            "minimum": 1
                                        }
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Contacts processed (partial success allowed).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "3 contacts added, 1 already in group"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "added_count": {
                                                    "type": "integer"
                                                },
                                                "already_in_group_count": {
                                                    "type": "integer"
                                                },
                                                "skipped_cross_pool_count": {
                                                    "type": "integer",
                                                    "description": "Number of contacts skipped because they belong to the other pool from the group's owner."
                                                },
                                                "not_found_count": {
                                                    "type": "integer"
                                                },
                                                "group_owner": {
                                                    "type": "string",
                                                    "enum": [
                                                        "self",
                                                        "parent"
                                                    ]
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            },
            "delete": {
                "summary": "Remove contacts from group",
                "description": "Removes the supplied contacts from the group (deletes rows from `contacts_to_groups`). Non-numeric contact IDs and IDs not actually in the group are silently skipped; the returned count reflects only rows that were actually deleted.",
                "tags": [
                    "Groups"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "contact_ids"
                                ],
                                "properties": {
                                    "contact_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer",
                                            "minimum": 1
                                        }
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Contacts removed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "3 contacts removed from group"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "removed_count": {
                                                    "type": "integer"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            },
            "put": {
                "summary": "Bulk update contact active status in group",
                "description": "Activates or deactivates every supplied contact's membership in the group in a single statement. All contacts must belong to the group owner's pool; if any do not, the entire request fails with 400.",
                "tags": [
                    "Groups"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "contact_ids",
                                    "active"
                                ],
                                "properties": {
                                    "contact_ids": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer",
                                            "minimum": 1
                                        }
                                    },
                                    "active": {
                                        "type": "integer",
                                        "enum": [
                                            0,
                                            1
                                        ],
                                        "description": "0 to deactivate, 1 to activate. Any truthy/falsy value is accepted and coerced."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Memberships updated.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "5 contact(s) activated in group"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "updated": {
                                                    "type": "integer",
                                                    "description": "Number of contacts_to_groups rows whose `active` value actually changed."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            }
        },
        "/groups/{id}/contacts/{contact_id}/active": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Group ID"
                },
                {
                    "name": "contact_id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Contact ID"
                }
            ],
            "put": {
                "summary": "Update a single contact's active status in a group",
                "description": "Activates or deactivates one contact's membership in the group. The contact must belong to the group owner's pool, and must already be a member of the group (otherwise 404).",
                "tags": [
                    "Groups"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "active"
                                ],
                                "properties": {
                                    "active": {
                                        "type": "integer",
                                        "enum": [
                                            0,
                                            1
                                        ],
                                        "description": "0 to deactivate, 1 to activate. Any truthy/falsy value is accepted and coerced."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Membership updated.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Contact activated in group"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "updated": {
                                                    "type": "integer",
                                                    "example": 1
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "Group not found, contact not found in the group's owner pool, or contact is not a member of this group.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            }
        },
        "/groups/{id}/clone": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Source group ID (must be owned by the calling user's parent account)"
                }
            ],
            "post": {
                "summary": "Clone a parent-owned group into your own pool",
                "description": "Creates an empty copy of the specified parent group's name and description in the calling user's own pool. Memberships are NOT copied (cross-pool memberships are forbidden by the pool-isolation invariant). Fails with 409 if a group of the same name already exists in the caller's own pool. Requires `parent_contact_access` of `view` or `manage`.",
                "tags": [
                    "Groups"
                ],
                "responses": {
                    "200": {
                        "description": "Cloned successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "group_id": {
                                                    "type": "integer",
                                                    "description": "Identifier of the newly cloned group in the caller's own pool"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "description": "No parent contact access (calling user is not a subaccount, or `parent_contact_access` is `none`)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Source group not found in parent pool",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "A group with the same name already exists in the caller's own pool",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/import": {
            "post": {
                "summary": "Import contacts (single request)",
                "description": "Import contacts in a single request. Supports two content types:\n\n**application/json** — Send pre-processed contacts as a JSON array. Accepts friendly field names (mobile, name, first_name, last_name, email, company) which are mapped to internal fields automatically. first_name + last_name are auto-combined into display_name if name is not provided.\n\n**multipart/form-data** — Upload a CSV, TSV, TXT, XLS, or XLSX file with column-to-field mappings. The file is parsed, validated, and imported in one step.\n\nBoth `group_ids` and `groups` can be specified at the batch level (applied to all contacts) and per-contact level (applied to that contact only). All group assignments are merged together. The two fields are strictly separate: `group_ids` values are always treated as integer IDs and the caller must own each one (batch-level returns 400 on any unowned ID; per-contact silently skips), while `groups` values are always treated as names — even if they look like numbers — and groups that don't exist are auto-created. A CSV/Excel column mapped to target `groups` is treated identically to the JSON `groups` field (always names).\n\n**Every imported contact must end up in at least one group.** For JSON imports, this means batch-level `group_ids`/`groups` must be supplied, OR every contact must carry its own per-contact `group_ids`/`groups`. For multipart imports, batch-level `group_ids` or `groups` is required (when a `groups` column is also mapped, this serves as the fallback for rows where the column is empty). Requests that would leave any contact groupless are rejected with 400.",
                "tags": [
                    "Import"
                ],
                "security": [
                    {
                        "BearerAuth": []
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "contacts"
                                ],
                                "properties": {
                                    "contacts": {
                                        "type": "array",
                                        "description": "Array of contact objects. Maximum 10,000 per request.",
                                        "maxItems": 10000,
                                        "items": {
                                            "type": "object",
                                            "required": [
                                                "mobile"
                                            ],
                                            "properties": {
                                                "mobile": {
                                                    "type": "string",
                                                    "description": "Mobile phone number (e.g. 0412345678, +61412345678). Also accepts 'phone' or 'gsm_number'."
                                                },
                                                "name": {
                                                    "type": "string",
                                                    "description": "Display name. Also accepts 'display_name'. Max 80 characters."
                                                },
                                                "first_name": {
                                                    "type": "string",
                                                    "description": "First name. Auto-combined with last_name into display_name if name is not provided. Max 40 characters."
                                                },
                                                "last_name": {
                                                    "type": "string",
                                                    "description": "Last name. Auto-combined with first_name into display_name if name is not provided. Max 40 characters."
                                                },
                                                "email": {
                                                    "type": "string",
                                                    "format": "email",
                                                    "description": "Email address. Mailbox format ('Name <user@host>') is accepted; the address between angle brackets is extracted."
                                                },
                                                "company": {
                                                    "type": "string",
                                                    "description": "Company/description. Also accepts 'description'. Max 80 characters."
                                                },
                                                "group_ids": {
                                                    "type": "array",
                                                    "description": "Group IDs to assign this contact to. Unowned IDs are silently dropped at the per-contact level.",
                                                    "items": {
                                                        "type": "integer"
                                                    }
                                                },
                                                "groups": {
                                                    "type": "array",
                                                    "description": "Group names to assign this contact to. Groups are auto-created if they don't exist.",
                                                    "items": {
                                                        "type": "string"
                                                    }
                                                }
                                            },
                                            "additionalProperties": {
                                                "description": "Custom field values keyed as `custom_<field_id>`. Max 60 characters per value."
                                            }
                                        }
                                    },
                                    "group_ids": {
                                        "type": "array",
                                        "description": "Group IDs to assign ALL imported contacts to. Any unowned ID returns 400.",
                                        "items": {
                                            "type": "integer"
                                        }
                                    },
                                    "groups": {
                                        "type": "array",
                                        "description": "Group names to assign ALL imported contacts to. Groups are auto-created if they don't exist.",
                                        "items": {
                                            "type": "string"
                                        }
                                    },
                                    "duplicate_handling": {
                                        "type": "string",
                                        "enum": [
                                            "skip",
                                            "update",
                                            "replace"
                                        ],
                                        "default": "skip",
                                        "description": "How to handle contacts with duplicate mobile numbers. 'skip' leaves existing contacts unchanged, 'update' merges non-empty fields, 'replace' overwrites all fields."
                                    },
                                    "owner": {
                                        "type": "string",
                                        "enum": [
                                            "self",
                                            "parent"
                                        ],
                                        "default": "self",
                                        "description": "Which pool to import the contacts into. Requires `parent_contact_access` of `manage` when set to `parent`. Group-name and field-name references in the request resolve within the chosen pool only (auto-creating in that pool if missing)."
                                    }
                                }
                            },
                            "example": {
                                "contacts": [
                                    {
                                        "mobile": "0412345678",
                                        "name": "John Smith",
                                        "email": "john@example.com",
                                        "company": "Acme Corp"
                                    },
                                    {
                                        "mobile": "0423456789",
                                        "first_name": "Jane",
                                        "last_name": "Doe",
                                        "groups": [
                                            "Staff"
                                        ]
                                    }
                                ],
                                "groups": [
                                    "API Imports"
                                ],
                                "duplicate_handling": "skip"
                            }
                        },
                        "multipart/form-data": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "file",
                                    "mappings"
                                ],
                                "properties": {
                                    "file": {
                                        "type": "string",
                                        "format": "binary",
                                        "description": "File to import. Supported: CSV, TSV, TXT, XLS, XLSX. Max 50MB."
                                    },
                                    "mappings": {
                                        "type": "string",
                                        "description": "JSON string mapping columns to field targets. Keys can be column indices (0-based) or column names (matched case-insensitively against file headers). Both can be mixed in the same mapping. Targets: gsm_number, display_name, first_name, last_name, email, description, groups, custom_<id>. Values accept shorthand strings (e.g. \"gsm_number\") or objects (e.g. {\"target\":\"gsm_number\"}).",
                                        "example": "{\"Mobile\":\"gsm_number\",\"First Name\":\"first_name\",\"2\":\"email\"}"
                                    },
                                    "has_header_row": {
                                        "type": "string",
                                        "enum": [
                                            "0",
                                            "1"
                                        ],
                                        "default": "1",
                                        "description": "Whether the file has a header row. Set to '0' if not."
                                    },
                                    "group_ids": {
                                        "type": "string",
                                        "description": "JSON array of group IDs to assign all contacts to.",
                                        "example": "[5, 12]"
                                    },
                                    "groups": {
                                        "type": "string",
                                        "description": "JSON array of group names to assign all contacts to.",
                                        "example": "[\"Staff\", \"VIP\"]"
                                    },
                                    "duplicate_handling": {
                                        "type": "string",
                                        "enum": [
                                            "skip",
                                            "update",
                                            "replace"
                                        ],
                                        "default": "skip",
                                        "description": "How to handle duplicate mobile numbers."
                                    },
                                    "sheet_index": {
                                        "type": "string",
                                        "default": "0",
                                        "description": "Sheet index for Excel files (0-based)."
                                    },
                                    "owner": {
                                        "type": "string",
                                        "enum": [
                                            "self",
                                            "parent"
                                        ],
                                        "default": "self",
                                        "description": "Which pool to import the contacts into. Requires `parent_contact_access` of `manage` when set to `parent`. Group-name and field-name references in the file resolve within the chosen pool only (auto-creating in that pool if missing)."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Import completed",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Import completed successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "processed": {
                                                    "type": "integer",
                                                    "description": "Total contacts processed (rows that were not blank)."
                                                },
                                                "created": {
                                                    "type": "integer",
                                                    "description": "New contacts created."
                                                },
                                                "updated": {
                                                    "type": "integer",
                                                    "description": "Existing contacts updated."
                                                },
                                                "skipped": {
                                                    "type": "integer",
                                                    "description": "Duplicates skipped."
                                                },
                                                "errors": {
                                                    "type": "integer",
                                                    "description": "Contacts that failed validation."
                                                },
                                                "warnings": {
                                                    "type": "integer",
                                                    "description": "Contacts with non-fatal warnings (e.g. invalid email)."
                                                },
                                                "issues": {
                                                    "type": "array",
                                                    "description": "Details of skipped, errored, or warned contacts.",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "row": {
                                                                "type": "integer",
                                                                "description": "1-based row/index number."
                                                            },
                                                            "type": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "error",
                                                                    "warning",
                                                                    "skipped"
                                                                ]
                                                            },
                                                            "identifier": {
                                                                "type": "string",
                                                                "description": "Mobile number or '-' if unknown."
                                                            },
                                                            "reason": {
                                                                "type": "string"
                                                            },
                                                            "duplicate_match": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "duplicate_self",
                                                                    "duplicate_parent"
                                                                ],
                                                                "description": "Present when the row matched an existing contact. `duplicate_self` = match in the target pool; `duplicate_parent` = match in the other readable pool (opposite of `owner`)."
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                },
                                "example": {
                                    "success": true,
                                    "message": "Import completed successfully",
                                    "data": {
                                        "processed": 3,
                                        "created": 2,
                                        "updated": 0,
                                        "skipped": 1,
                                        "errors": 0,
                                        "warnings": 0,
                                        "issues": [
                                            {
                                                "row": 1,
                                                "type": "skipped",
                                                "identifier": "61412345678",
                                                "reason": "Duplicate number",
                                                "duplicate_match": "duplicate_self"
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "description": "Caller lacks permission to import into the requested owner pool."
                    },
                    "413": {
                        "description": "Form body exceeds `post_max_size`."
                    },
                    "415": {
                        "description": "Unsupported Content-Type."
                    }
                }
            }
        },
        "/import/sheets": {
            "post": {
                "summary": "List Excel sheet names",
                "description": "Inspects an uploaded XLS/XLSX file and returns its sheet names. Non-Excel files return an empty `sheets` array with `has_multiple_sheets: false`. Used by the multi-step import UI to let the user pick a sheet before parsing.",
                "tags": [
                    "Import"
                ],
                "security": [
                    {
                        "BearerAuth": []
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "multipart/form-data": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "file"
                                ],
                                "properties": {
                                    "file": {
                                        "type": "string",
                                        "format": "binary",
                                        "description": "Excel file (XLS or XLSX). Max 50MB."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Sheet names retrieved.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Sheet names retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "sheets": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "index": {
                                                                "type": "integer",
                                                                "description": "0-based sheet index."
                                                            },
                                                            "name": {
                                                                "type": "string"
                                                            }
                                                        }
                                                    }
                                                },
                                                "has_multiple_sheets": {
                                                    "type": "boolean"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/import/parse": {
            "post": {
                "summary": "Parse import file (multi-step)",
                "description": "Step 1 of 3 in the multi-step import flow. Uploads a file, parses headers, and returns a preview of the first 10 rows along with the total row count. Stores file metadata in the PHP session under a key scoped to the caller's user_id, so subsequent validate and execute requests must share the same session cookie.",
                "tags": [
                    "Import"
                ],
                "security": [
                    {
                        "BearerAuth": []
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "multipart/form-data": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "file"
                                ],
                                "properties": {
                                    "file": {
                                        "type": "string",
                                        "format": "binary",
                                        "description": "File to parse. Supported: CSV, TSV, TXT, XLS, XLSX. Max 50MB."
                                    },
                                    "has_header_row": {
                                        "type": "string",
                                        "enum": [
                                            "0",
                                            "1"
                                        ],
                                        "default": "1",
                                        "description": "Whether the first row is a header. When '0', synthetic headers ('Column A', 'Column B', ...) are generated."
                                    },
                                    "sheet_index": {
                                        "type": "string",
                                        "default": "0",
                                        "description": "Sheet index for Excel files (0-based). Ignored for CSV/TSV."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "File parsed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "File parsed successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "headers": {
                                                    "type": "array",
                                                    "description": "Column header names (from the header row, or synthetic 'Column A'…'Column Z'… names if `has_header_row=0`).",
                                                    "items": {
                                                        "type": "string"
                                                    }
                                                },
                                                "preview": {
                                                    "type": "array",
                                                    "description": "First 10 data rows. Each row is an array of cell values, padded to match the header count.",
                                                    "items": {
                                                        "type": "array",
                                                        "items": {
                                                            "type": "string"
                                                        }
                                                    }
                                                },
                                                "total_rows": {
                                                    "type": "integer",
                                                    "description": "Total non-blank data rows in the file."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/import/validate": {
            "post": {
                "summary": "Validate parsed data (multi-step)",
                "description": "Step 2 of 3 in the multi-step import flow. Streams through the parsed file with the supplied column mappings, returning row counts and a preview of the first 20 validated rows. Tags rows as `duplicate_self` / `duplicate_parent` / `new` based on existing contacts in the readable pools. Stores the mappings in session for the execute step. Requires the session cookie from `/import/parse`.",
                "tags": [
                    "Import"
                ],
                "security": [
                    {
                        "BearerAuth": []
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "mappings"
                                ],
                                "properties": {
                                    "mappings": {
                                        "type": "object",
                                        "description": "Column index (or special key 'displayname_combined') → target. Values may be a string target or `{\"target\": \"<target>\"}`. Targets: gsm_number, display_name, email, description, groups, custom_<id>.",
                                        "additionalProperties": true
                                    },
                                    "target_group_ids": {
                                        "type": "array",
                                        "description": "Accepted but not used by the validate step — retained for client compatibility. Ownership is enforced at execute time.",
                                        "items": {
                                            "type": "integer",
                                            "minimum": 1
                                        }
                                    },
                                    "owner": {
                                        "type": "string",
                                        "enum": [
                                            "self",
                                            "parent"
                                        ],
                                        "default": "self",
                                        "description": "Pool used for duplicate-detection preview. Must match the value sent to `/import/execute`."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Validation completed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Data validated successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "total": {
                                                    "type": "integer",
                                                    "description": "Total rows processed."
                                                },
                                                "valid": {
                                                    "type": "integer",
                                                    "description": "Rows that passed validation."
                                                },
                                                "errors": {
                                                    "type": "integer",
                                                    "description": "Rows with fatal validation errors (e.g. missing/invalid mobile)."
                                                },
                                                "warnings": {
                                                    "type": "integer",
                                                    "description": "Valid rows with non-fatal warnings (e.g. invalid email)."
                                                },
                                                "duplicate_self": {
                                                    "type": "integer",
                                                    "description": "Rows whose number already exists in the target pool."
                                                },
                                                "duplicate_parent": {
                                                    "type": "integer",
                                                    "description": "Rows whose number exists in the other readable pool (opposite of `owner`)."
                                                },
                                                "preview": {
                                                    "type": "array",
                                                    "description": "First 20 validated rows.",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "valid": {
                                                                "type": "boolean"
                                                            },
                                                            "issues": {
                                                                "type": "array",
                                                                "items": {
                                                                    "type": "string"
                                                                }
                                                            },
                                                            "warnings": {
                                                                "type": "array",
                                                                "items": {
                                                                    "type": "string"
                                                                }
                                                            },
                                                            "display_name": {
                                                                "type": "string"
                                                            },
                                                            "gsm_number": {
                                                                "type": "string",
                                                                "description": "Cleaned/normalized number, or empty if invalid."
                                                            },
                                                            "raw_gsm_number": {
                                                                "type": "string",
                                                                "description": "Original value from the file."
                                                            },
                                                            "email": {
                                                                "type": "string"
                                                            },
                                                            "description": {
                                                                "type": "string"
                                                            },
                                                            "custom_fields": {
                                                                "type": "object",
                                                                "additionalProperties": {
                                                                    "type": "string"
                                                                }
                                                            },
                                                            "groups": {
                                                                "type": "array",
                                                                "description": "Group names extracted from the mapped 'groups' column (semicolon-separated in the source).",
                                                                "items": {
                                                                    "type": "string"
                                                                }
                                                            },
                                                            "duplicate_match": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "new",
                                                                    "duplicate_self",
                                                                    "duplicate_parent"
                                                                ]
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "description": "Caller lacks permission to import into the requested owner pool."
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/import/execute": {
            "post": {
                "summary": "Execute import (multi-step)",
                "description": "Step 3 of 3 in the multi-step import flow. Streams the parsed file from the session-stored temp file and inserts/updates contacts in batches. Requires the session cookie from `/import/parse`. Cleans up the temp file and session keys on completion. Set `streaming: true` to receive Server-Sent Events with progress updates and a final `complete` event instead of a single JSON body.\n\n**Every imported contact must end up in at least one group.** At least one of `target_group_ids` or `default_group_id` must be supplied — when a `groups` column is mapped, the default bucket is used for rows where the column is empty (mutually exclusive, not merged). Requests that would leave any contact groupless are rejected with 400. All supplied group IDs are ownership-checked up front.",
                "tags": [
                    "Import"
                ],
                "security": [
                    {
                        "BearerAuth": []
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "mappings": {
                                        "type": "object",
                                        "description": "Optional override of the mappings stored by `/import/validate`. Same shape as the validate-step `mappings` field.",
                                        "additionalProperties": true
                                    },
                                    "streaming": {
                                        "type": "boolean",
                                        "default": false,
                                        "description": "Enable SSE streaming. When true, responds with `text/event-stream` carrying `progress` events (`{type, percentage, stats, issues}`) and a final `complete` event (`{type, stats}`)."
                                    },
                                    "duplicate_handling": {
                                        "type": "string",
                                        "enum": [
                                            "skip",
                                            "update",
                                            "replace"
                                        ],
                                        "default": "skip"
                                    },
                                    "target_group_ids": {
                                        "type": "array",
                                        "description": "Group IDs applied to every row that has no value in a mapped 'groups' column. Required (along with or in lieu of `default_group_id`) so every contact ends up in at least one group. The caller must own each ID.",
                                        "items": {
                                            "type": "integer"
                                        }
                                    },
                                    "default_group_id": {
                                        "type": "integer",
                                        "description": "Fallback group ID merged into the default bucket alongside `target_group_ids`. The caller must own this group."
                                    },
                                    "owner": {
                                        "type": "string",
                                        "enum": [
                                            "self",
                                            "parent"
                                        ],
                                        "default": "self",
                                        "description": "Which pool to import the contacts into. Requires `parent_contact_access` of `manage` when set to `parent`. Group-name and field-name references in the file resolve within the chosen pool only (auto-creating in that pool if missing)."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Import completed. Non-streaming responses use the schema below; streaming responses use `text/event-stream` carrying `progress` and `complete` events whose `stats` payload matches the `data` object below.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Import completed successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "processed": {
                                                    "type": "integer"
                                                },
                                                "created": {
                                                    "type": "integer"
                                                },
                                                "updated": {
                                                    "type": "integer"
                                                },
                                                "skipped": {
                                                    "type": "integer"
                                                },
                                                "errors": {
                                                    "type": "integer"
                                                },
                                                "warnings": {
                                                    "type": "integer"
                                                },
                                                "issues": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "row": {
                                                                "type": "integer"
                                                            },
                                                            "type": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "error",
                                                                    "warning",
                                                                    "skipped"
                                                                ]
                                                            },
                                                            "identifier": {
                                                                "type": "string"
                                                            },
                                                            "reason": {
                                                                "type": "string"
                                                            },
                                                            "duplicate_match": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "duplicate_self",
                                                                    "duplicate_parent"
                                                                ]
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            },
                            "text/event-stream": {
                                "schema": {
                                    "type": "string",
                                    "description": "SSE stream. Each event is `data: <json>\\n\\n`. `progress` events: `{type:\"progress\", percentage, stats, issues}`. Final event: `{type:\"complete\", stats}`."
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "description": "Caller lacks permission to import into the requested owner pool."
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/interactive": {
            "get": {
                "summary": "List keywords",
                "description": "Returns all interactive SMS keywords belonging to the authenticated user (or the effective user when acting on behalf of another account), ordered alphabetically by keyword. The `search_criteria` value `begins` is returned as `begins with` and `ends` as `ends with` for display.",
                "tags": [
                    "Interactive"
                ],
                "responses": {
                    "200": {
                        "description": "Keywords retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Keywords retrieved successfully"
                                        },
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "type": "object",
                                                "properties": {
                                                    "interactive_sms_id": {
                                                        "type": "integer"
                                                    },
                                                    "keyword": {
                                                        "type": "string"
                                                    },
                                                    "search_criteria": {
                                                        "type": "string",
                                                        "enum": [
                                                            "contains",
                                                            "is",
                                                            "begins with",
                                                            "ends with"
                                                        ],
                                                        "description": "Display form: stored values `begins` and `ends` are returned as `begins with` and `ends with`."
                                                    },
                                                    "reply_text": {
                                                        "type": "string"
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "post": {
                "summary": "Create keyword",
                "description": "Creates a new interactive SMS keyword and automated reply for the authenticated user. Requires the `manage_interactive` permission when acting on behalf of another user. Returns 409 if the keyword already exists for the user.",
                "tags": [
                    "Interactive"
                ],
                "responses": {
                    "200": {
                        "description": "Keyword created successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Keyword created successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "interactive_sms_id": {
                                                    "type": "integer"
                                                },
                                                "keyword": {
                                                    "type": "string"
                                                },
                                                "search_criteria": {
                                                    "type": "string",
                                                    "enum": [
                                                        "contains",
                                                        "is",
                                                        "begins",
                                                        "ends"
                                                    ]
                                                },
                                                "reply_text": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "409": {
                        "description": "Keyword already exists for this user.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": false
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Keyword already exists"
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "keyword",
                                    "search_criteria",
                                    "reply_text"
                                ],
                                "properties": {
                                    "keyword": {
                                        "type": "string",
                                        "maxLength": 20
                                    },
                                    "search_criteria": {
                                        "type": "string",
                                        "enum": [
                                            "contains",
                                            "is",
                                            "begins",
                                            "ends"
                                        ]
                                    },
                                    "reply_text": {
                                        "type": "string",
                                        "maxLength": 160
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/interactive/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Interactive keyword ID"
                }
            ],
            "get": {
                "summary": "Get keyword",
                "description": "Returns a single interactive SMS keyword owned by the authenticated user. The `search_criteria` value `begins` is returned as `begins with` and `ends` as `ends with` for display.",
                "tags": [
                    "Interactive"
                ],
                "responses": {
                    "200": {
                        "description": "Keyword retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Keyword retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "interactive_sms_id": {
                                                    "type": "integer"
                                                },
                                                "keyword": {
                                                    "type": "string"
                                                },
                                                "search_criteria": {
                                                    "type": "string",
                                                    "enum": [
                                                        "contains",
                                                        "is",
                                                        "begins with",
                                                        "ends with"
                                                    ],
                                                    "description": "Display form: stored values `begins` and `ends` are returned as `begins with` and `ends with`."
                                                },
                                                "reply_text": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "put": {
                "summary": "Update keyword",
                "description": "Partially updates an interactive SMS keyword owned by the authenticated user. Any subset of `keyword`, `search_criteria`, and `reply_text` may be supplied; at least one field is required. Requires the `manage_interactive` permission when acting on behalf of another user. The `PATCH` method is accepted with identical behaviour.",
                "tags": [
                    "Interactive"
                ],
                "responses": {
                    "200": {
                        "description": "Keyword updated successfully. `data` is null.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Interactive SMS keyword updated successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "nullable": true
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                },
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "keyword": {
                                        "type": "string",
                                        "maxLength": 20
                                    },
                                    "search_criteria": {
                                        "type": "string",
                                        "enum": [
                                            "contains",
                                            "is",
                                            "begins",
                                            "ends"
                                        ]
                                    },
                                    "reply_text": {
                                        "type": "string",
                                        "maxLength": 160
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                }
            },
            "patch": {
                "summary": "Update keyword (alias)",
                "description": "Alias for `PUT /interactive/{id}` with identical semantics. Partially updates an interactive SMS keyword.",
                "tags": [
                    "Interactive"
                ],
                "responses": {
                    "200": {
                        "description": "Keyword updated successfully. `data` is null.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Interactive SMS keyword updated successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "nullable": true
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                },
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "keyword": {
                                        "type": "string",
                                        "maxLength": 20
                                    },
                                    "search_criteria": {
                                        "type": "string",
                                        "enum": [
                                            "contains",
                                            "is",
                                            "begins",
                                            "ends"
                                        ]
                                    },
                                    "reply_text": {
                                        "type": "string",
                                        "maxLength": 160
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                }
            },
            "delete": {
                "summary": "Delete keyword",
                "description": "Deletes an interactive SMS keyword owned by the authenticated user. Requires the `manage_interactive` permission when acting on behalf of another user. Returns 404 if no matching row is deleted.",
                "tags": [
                    "Interactive"
                ],
                "responses": {
                    "200": {
                        "description": "Keyword deleted successfully. `data` is null.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Interactive SMS keyword deleted successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "nullable": true
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/messages": {
            "get": {
                "summary": "Message history",
                "description": "Returns a paginated list of messages for the authenticated account. Use `direction` to choose outgoing-only, incoming-only, or a combined feed. `direction=all` and `direction=incoming` route through dedicated handlers that build a UNION view; `direction=outgoing` uses the legacy messages-table path.",
                "tags": [
                    "Messages"
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/Limit"
                    },
                    {
                        "$ref": "#/components/parameters/Search"
                    },
                    {
                        "name": "direction",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "outgoing",
                                "incoming"
                            ],
                            "default": "all"
                        },
                        "description": "Filter by message direction. Invalid values fall back to `all`."
                    },
                    {
                        "name": "account",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "default": "this"
                        },
                        "description": "Account scope: `this` (current account only), `all` (current + all subaccounts), or a numeric subaccount user_id (ownership is validated)."
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Filter by status. Outgoing: raw `messages.status` value (`0`=Queued, `1`/`3`=Success, `2`=Failed). Incoming (via direction=incoming): `reply` or `unsolicited`."
                    },
                    {
                        "name": "date_from",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Start of date range (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS), interpreted in the given `timezone`."
                    },
                    {
                        "name": "date_to",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "End of date range (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS), interpreted in the given `timezone`."
                    },
                    {
                        "name": "timezone",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "default": "Australia/Melbourne"
                        },
                        "description": "IANA timezone used to interpret `date_from`/`date_to` before they are converted to server time."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Paginated message list.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "messages": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/MessageHistoryItem"
                                                    },
                                                    "description": "Each item also includes `success_count`, `failed_count`, `success_percentage`, `reply_count`, `latest_reply`, `long_sms`, `cost_per_message`, `duplicates`, `invalid_numbers`, and (for MMS) `image_urls` depending on `direction`."
                                                },
                                                "pagination": {
                                                    "$ref": "#/components/schemas/MessagesPagination"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/messages/stats": {
            "get": {
                "summary": "Message statistics",
                "description": "Returns aggregated counts for outgoing and/or incoming messages on the authenticated account. The `direction` parameter selects which statistics to compute; combined totals are returned when `direction=all`.",
                "tags": [
                    "Messages"
                ],
                "parameters": [
                    {
                        "name": "direction",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "outgoing",
                                "incoming"
                            ],
                            "default": "all"
                        },
                        "description": "Which statistics to compute. Invalid values fall back to `all`."
                    },
                    {
                        "name": "date_from",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Start of date range (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)."
                    },
                    {
                        "name": "date_to",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "End of date range (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Aggregated message statistics.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "total_messages": {
                                                    "type": "integer"
                                                },
                                                "outgoing_count": {
                                                    "type": "integer"
                                                },
                                                "incoming_count": {
                                                    "type": "integer"
                                                },
                                                "today_count": {
                                                    "type": "integer"
                                                },
                                                "week_count": {
                                                    "type": "integer",
                                                    "description": "Messages in the last 7 days."
                                                },
                                                "success_count": {
                                                    "type": "integer",
                                                    "description": "Outgoing messages with status `1` or `3`."
                                                },
                                                "failed_count": {
                                                    "type": "integer",
                                                    "description": "Outgoing messages with status `2`."
                                                },
                                                "total_cost": {
                                                    "type": "number",
                                                    "description": "Sum of recipient charges, excluding statuses `2`/`3`/`5`."
                                                },
                                                "success_percentage": {
                                                    "type": "number"
                                                },
                                                "failed_percentage": {
                                                    "type": "number"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/messages/export": {
            "get": {
                "summary": "Export message history",
                "description": "Streams a UTF-8 CSV of message history with the same filters as `GET /messages`. Direction selects outgoing-only, incoming-only, or a combined chronological export.",
                "tags": [
                    "Messages"
                ],
                "parameters": [
                    {
                        "name": "direction",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "outgoing",
                                "incoming"
                            ],
                            "default": "all"
                        }
                    },
                    {
                        "name": "account",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "default": "this"
                        },
                        "description": "Account scope: `this`, `all`, or a numeric subaccount user_id."
                    },
                    {
                        "$ref": "#/components/parameters/Search"
                    },
                    {
                        "name": "date_from",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Start of date range (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)."
                    },
                    {
                        "name": "date_to",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "End of date range (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)."
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Filter by raw outgoing status code."
                    },
                    {
                        "name": "timezone",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "default": "Australia/Melbourne"
                        },
                        "description": "IANA timezone used to interpret date filters and format timestamps in the CSV."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "CSV file (`Content-Disposition: attachment`).",
                        "content": {
                            "text/csv": []
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/messages/incoming": {
            "get": {
                "summary": "Incoming messages",
                "description": "Lists incoming messages (replies and unsolicited inbound SMS/MMS) for the authenticated account. When `action=export` is supplied a CSV is streamed instead of JSON; `action=stats` is an alias for `GET /messages/incoming/stats`.",
                "tags": [
                    "Messages"
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/Limit"
                    },
                    {
                        "$ref": "#/components/parameters/Search"
                    },
                    {
                        "name": "account",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "default": "this"
                        },
                        "description": "Account scope: `this`, `all`, or a numeric subaccount user_id."
                    },
                    {
                        "name": "type",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "reply",
                                "unsolicited"
                            ]
                        },
                        "description": "Filter by inbound type: `reply` (linked to an outgoing message) or `unsolicited`."
                    },
                    {
                        "name": "date_from",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "date_to",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "action",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "export",
                                "stats"
                            ]
                        },
                        "description": "`export` streams a CSV (add `id=<incoming_mess_id>` to export a single message). `stats` returns the incoming statistics payload."
                    },
                    {
                        "name": "id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "minimum": 1
                        },
                        "description": "Only used when `action=export`; exports a single incoming message by `incoming_mess_id`."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "JSON list, CSV export, or incoming stats depending on `action`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "incoming": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/MessageHistoryItem"
                                                    },
                                                    "description": "Each item exposes `incoming_message_id`, `sender_name`, `message_type` (`reply`/`unsolicited`), `original_message_id`, `original_message`, `original_send_datetime`, `original_type`, and (for MMS) `image_urls`/`original_image_urls`."
                                                },
                                                "pagination": {
                                                    "$ref": "#/components/schemas/MessagesPagination"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            },
                            "text/csv": []
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    }
                }
            }
        },
        "/messages/incoming/stats": {
            "get": {
                "summary": "Incoming message statistics",
                "description": "Returns aggregated statistics for incoming messages on the authenticated account, including reply vs. unsolicited counts and a today-vs-yesterday change percentage.",
                "tags": [
                    "Messages"
                ],
                "parameters": [
                    {
                        "name": "date_from",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "date_to",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Incoming message statistics.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "total_messages": {
                                                    "type": "integer"
                                                },
                                                "replies_count": {
                                                    "type": "integer"
                                                },
                                                "unsolicited_count": {
                                                    "type": "integer"
                                                },
                                                "today_count": {
                                                    "type": "integer"
                                                },
                                                "week_count": {
                                                    "type": "integer"
                                                },
                                                "yesterday_count": {
                                                    "type": "integer"
                                                },
                                                "unique_senders": {
                                                    "type": "integer"
                                                },
                                                "replies_percentage": {
                                                    "type": "number"
                                                },
                                                "unsolicited_percentage": {
                                                    "type": "number"
                                                },
                                                "today_change": {
                                                    "type": "number",
                                                    "description": "Percent change in today's count vs. yesterday."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/messages/incoming/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Incoming message ID (`incoming_mess_id`)."
                }
            ],
            "get": {
                "summary": "Incoming message detail",
                "description": "Returns the full incoming message record including sender name, original outgoing message context, MMS image URLs (when applicable), and the credit cost.",
                "tags": [
                    "Messages"
                ],
                "responses": {
                    "200": {
                        "description": "Incoming message details.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "incoming_message_id": {
                                                    "type": "integer"
                                                },
                                                "sender": {
                                                    "type": "string"
                                                },
                                                "sender_name": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "recipient": {
                                                    "type": "string"
                                                },
                                                "message": {
                                                    "type": "string"
                                                },
                                                "receive_datetime": {
                                                    "type": "string",
                                                    "format": "date-time"
                                                },
                                                "message_type": {
                                                    "type": "string",
                                                    "enum": [
                                                        "reply",
                                                        "unsolicited"
                                                    ]
                                                },
                                                "original_message_id": {
                                                    "type": "integer",
                                                    "nullable": true
                                                },
                                                "original_message": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "original_send_datetime": {
                                                    "type": "string",
                                                    "format": "date-time",
                                                    "nullable": true
                                                },
                                                "total_cost": {
                                                    "type": "number"
                                                },
                                                "type": {
                                                    "type": "string",
                                                    "enum": [
                                                        "SMS",
                                                        "MMS"
                                                    ]
                                                },
                                                "original_type": {
                                                    "type": "string",
                                                    "enum": [
                                                        "SMS",
                                                        "MMS"
                                                    ]
                                                },
                                                "image_urls": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "string"
                                                    },
                                                    "description": "Present when `type` is `MMS`."
                                                },
                                                "original_image_urls": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "string"
                                                    },
                                                    "description": "Present when `original_type` is `MMS`."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/messages/outgoing/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Internal outgoing message ID (numeric `messages.message_id`)."
                }
            ],
            "get": {
                "summary": "Get outgoing message",
                "description": "Returns the core fields of a single outgoing message. `total_cost` is recomputed from `message_recipients` and excludes recipients with status `2`/`3`/`5` (failed/invalid/blocked).",
                "tags": [
                    "Messages"
                ],
                "responses": {
                    "200": {
                        "description": "Outgoing message summary.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "integer"
                                                },
                                                "message": {
                                                    "type": "string"
                                                },
                                                "sender": {
                                                    "type": "string"
                                                },
                                                "status": {
                                                    "type": "string",
                                                    "enum": [
                                                        "Queued",
                                                        "Success",
                                                        "Failed",
                                                        "Unknown"
                                                    ]
                                                },
                                                "send_datetime": {
                                                    "type": "string",
                                                    "format": "date-time"
                                                },
                                                "recipients": {
                                                    "type": "integer"
                                                },
                                                "duplicates": {
                                                    "type": "integer"
                                                },
                                                "invalid_numbers": {
                                                    "type": "integer"
                                                },
                                                "cost_per_message": {
                                                    "type": "number"
                                                },
                                                "total_cost": {
                                                    "type": "number"
                                                },
                                                "delivery_reports": {
                                                    "type": "boolean"
                                                },
                                                "allow_replies": {
                                                    "type": "boolean"
                                                },
                                                "auto_optout": {
                                                    "type": "boolean"
                                                },
                                                "long_sms": {
                                                    "type": "boolean"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/messages/outgoing/{id}/details": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Internal outgoing message ID."
                }
            ],
            "get": {
                "summary": "Outgoing message details",
                "description": "Returns the outgoing message plus aggregated recipient statistics. When `delivery_reports` is enabled the response also includes `delivered_count` and `delivered_percentage`.",
                "tags": [
                    "Messages"
                ],
                "responses": {
                    "200": {
                        "description": "Outgoing message with statistics.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "integer"
                                                },
                                                "message": {
                                                    "type": "string"
                                                },
                                                "sender": {
                                                    "type": "string"
                                                },
                                                "status": {
                                                    "type": "string"
                                                },
                                                "send_datetime": {
                                                    "type": "string",
                                                    "format": "date-time"
                                                },
                                                "cost_per_message": {
                                                    "type": "number"
                                                },
                                                "type": {
                                                    "type": "string",
                                                    "enum": [
                                                        "SMS",
                                                        "MMS"
                                                    ]
                                                },
                                                "delivery_reports": {
                                                    "type": "boolean"
                                                },
                                                "allow_replies": {
                                                    "type": "boolean"
                                                },
                                                "auto_optout": {
                                                    "type": "boolean"
                                                },
                                                "long_sms": {
                                                    "type": "boolean"
                                                },
                                                "is_overstamped": {
                                                    "type": "boolean",
                                                    "description": "Whether the sender ID was overstamped at delivery time."
                                                },
                                                "original_sender": {
                                                    "type": "string",
                                                    "nullable": true,
                                                    "description": "The original sender ID before overstamping; null if not overstamped."
                                                },
                                                "routing": {
                                                    "type": "object",
                                                    "description": "Sender-ID routing outcome for this message.",
                                                    "properties": {
                                                        "overstamped_count": {
                                                            "type": "integer",
                                                            "description": "Recipients delivered with the sender overstamped to 'Unverified'."
                                                        },
                                                        "blocked_count": {
                                                            "type": "integer",
                                                            "description": "Recipients blocked by a routing rule (not delivered)."
                                                        },
                                                        "modified_count": {
                                                            "type": "integer",
                                                            "description": "Recipients whose sender ID was replaced by a routing rule."
                                                        },
                                                        "details": {
                                                            "type": "array",
                                                            "description": "Full per-(country, result) breakdown with the final delivered sender.",
                                                            "items": {
                                                                "type": "object",
                                                                "properties": {
                                                                    "country": {
                                                                        "type": "string",
                                                                        "description": "Recipient region (e.g. 'AU')."
                                                                    },
                                                                    "result": {
                                                                        "type": "string",
                                                                        "enum": [
                                                                            "allowed",
                                                                            "blocked",
                                                                            "modified",
                                                                            "unverified"
                                                                        ]
                                                                    },
                                                                    "final_sender": {
                                                                        "type": "string",
                                                                        "nullable": true,
                                                                        "description": "Sender as delivered when changed (replacement or 'Unverified'); null for allowed/blocked."
                                                                    },
                                                                    "recipients": {
                                                                        "type": "integer"
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                },
                                                "image_urls": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "string"
                                                    },
                                                    "description": "Present when `type` is `MMS`."
                                                },
                                                "statistics": {
                                                    "type": "object",
                                                    "properties": {
                                                        "total_recipients": {
                                                            "type": "integer"
                                                        },
                                                        "sent_count": {
                                                            "type": "integer"
                                                        },
                                                        "pending_count": {
                                                            "type": "integer"
                                                        },
                                                        "delivered_count": {
                                                            "type": "integer",
                                                            "description": "Only when `delivery_reports=true`."
                                                        },
                                                        "failed_count": {
                                                            "type": "integer"
                                                        },
                                                        "sent_percentage": {
                                                            "type": "number"
                                                        },
                                                        "pending_percentage": {
                                                            "type": "number"
                                                        },
                                                        "delivered_percentage": {
                                                            "type": "number",
                                                            "description": "Only when `delivery_reports=true`."
                                                        },
                                                        "failed_percentage": {
                                                            "type": "number"
                                                        },
                                                        "total_cost": {
                                                            "type": "number"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/messages/outgoing/{id}/recipients": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Internal outgoing message ID."
                }
            ],
            "get": {
                "summary": "Outgoing message recipients",
                "description": "Paginated list of recipients for an outgoing message including delivery status, charged cost and contact display name when available.",
                "tags": [
                    "Messages"
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/Limit"
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Filter by raw `message_recipients.status` code."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Recipients with pagination.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message_id": {
                                                    "type": "integer"
                                                },
                                                "recipients": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "recipient": {
                                                                "type": "string"
                                                            },
                                                            "contact_name": {
                                                                "type": "string",
                                                                "nullable": true
                                                            },
                                                            "status": {
                                                                "type": "string",
                                                                "description": "Derived from `provider_status` and `status`; values include `Pending`, `Waiting`, `Sent`, `Delivered`, `Read`, `Queued`, `Failed`, `Invalid`, `Blocked`."
                                                            },
                                                            "cost": {
                                                                "type": "number"
                                                            },
                                                            "sender": {
                                                                "type": "string"
                                                            },
                                                            "send_datetime": {
                                                                "type": "string",
                                                                "format": "date-time"
                                                            }
                                                        }
                                                    }
                                                },
                                                "pagination": {
                                                    "$ref": "#/components/schemas/MessagesPagination"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/messages/outgoing/{id}/replies": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Internal outgoing message ID."
                }
            ],
            "get": {
                "summary": "Replies to outgoing message",
                "description": "Paginated incoming messages that reference this outgoing message via `incoming_messages.mess_id`.",
                "tags": [
                    "Messages"
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/Limit"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Replies for the outgoing message.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message_id": {
                                                    "type": "integer"
                                                },
                                                "allow_replies": {
                                                    "type": "boolean"
                                                },
                                                "auto_optout": {
                                                    "type": "boolean"
                                                },
                                                "replies": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "incoming_mess_id": {
                                                                "type": "integer"
                                                            },
                                                            "from": {
                                                                "type": "string"
                                                            },
                                                            "contact_name": {
                                                                "type": "string",
                                                                "nullable": true
                                                            },
                                                            "to": {
                                                                "type": "string"
                                                            },
                                                            "message": {
                                                                "type": "string"
                                                            },
                                                            "date_received": {
                                                                "type": "string",
                                                                "format": "date-time"
                                                            },
                                                            "cost": {
                                                                "type": "number"
                                                            }
                                                        }
                                                    }
                                                },
                                                "pagination": {
                                                    "$ref": "#/components/schemas/MessagesPagination"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/messages/outgoing/{id}/export": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Internal outgoing message ID."
                }
            ],
            "get": {
                "summary": "Export outgoing message details",
                "description": "Streams a CSV containing the recipient list followed by an `INCOMING MESSAGES (REPLIES)` section (only emitted when replies exist).",
                "tags": [
                    "Messages"
                ],
                "responses": {
                    "200": {
                        "description": "CSV file.",
                        "content": {
                            "text/csv": []
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/messages/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string"
                    },
                    "description": "External `message_ref` string; resolved to an internal `message_id` for the authenticated account."
                }
            ],
            "get": {
                "summary": "Get message by reference",
                "description": "Returns the same payload as `GET /messages/outgoing/{id}` but accepts a customer-facing `message_ref` and resolves it to the internal message ID.",
                "tags": [
                    "Messages"
                ],
                "responses": {
                    "200": {
                        "description": "Outgoing message summary.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "integer"
                                                },
                                                "message": {
                                                    "type": "string"
                                                },
                                                "sender": {
                                                    "type": "string"
                                                },
                                                "status": {
                                                    "type": "string"
                                                },
                                                "send_datetime": {
                                                    "type": "string",
                                                    "format": "date-time"
                                                },
                                                "recipients": {
                                                    "type": "integer"
                                                },
                                                "duplicates": {
                                                    "type": "integer"
                                                },
                                                "invalid_numbers": {
                                                    "type": "integer"
                                                },
                                                "cost_per_message": {
                                                    "type": "number"
                                                },
                                                "total_cost": {
                                                    "type": "number"
                                                },
                                                "delivery_reports": {
                                                    "type": "boolean"
                                                },
                                                "allow_replies": {
                                                    "type": "boolean"
                                                },
                                                "auto_optout": {
                                                    "type": "boolean"
                                                },
                                                "long_sms": {
                                                    "type": "boolean"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/messages/{id}/details": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string"
                    },
                    "description": "External `message_ref` string."
                }
            ],
            "get": {
                "summary": "Message details by reference",
                "description": "Returns the same payload as `GET /messages/outgoing/{id}/details` but accepts the customer-facing `message_ref`.",
                "tags": [
                    "Messages"
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/messages/{id}/recipients": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string"
                    },
                    "description": "External `message_ref` string."
                }
            ],
            "get": {
                "summary": "Message recipients by reference",
                "description": "Paginated recipients for the resolved outgoing message. The recipient shape here differs slightly from `/messages/outgoing/{id}/recipients`: it returns `delivery_status` instead of `status` and omits the `sender` field.",
                "tags": [
                    "Messages"
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/Limit"
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Filter by raw `message_recipients.status` code."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Recipients with pagination.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "integer",
                                                    "description": "Internal message ID resolved from the path `message_ref`."
                                                },
                                                "recipients": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "recipient": {
                                                                "type": "string"
                                                            },
                                                            "contact_name": {
                                                                "type": "string"
                                                            },
                                                            "delivery_status": {
                                                                "type": "string",
                                                                "description": "Same vocabulary as `status` on `/messages/outgoing/{id}/recipients`."
                                                            },
                                                            "send_datetime": {
                                                                "type": "string",
                                                                "format": "date-time"
                                                            },
                                                            "cost": {
                                                                "type": "number"
                                                            }
                                                        }
                                                    }
                                                },
                                                "pagination": {
                                                    "$ref": "#/components/schemas/MessagesPagination"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/messages/{id}/replies": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string"
                    },
                    "description": "External `message_ref` string."
                }
            ],
            "get": {
                "summary": "Replies to message by reference",
                "description": "Paginated incoming messages linked to the resolved outgoing message. Pagination uses the shared `total_replies` shape.",
                "tags": [
                    "Messages"
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/Limit"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Replies for the message.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "integer"
                                                },
                                                "allow_replies": {
                                                    "type": "boolean"
                                                },
                                                "auto_optout": {
                                                    "type": "boolean"
                                                },
                                                "replies": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "id": {
                                                                "type": "integer",
                                                                "description": "`incoming_mess_id`."
                                                            },
                                                            "from": {
                                                                "type": "string"
                                                            },
                                                            "contact_name": {
                                                                "type": "string",
                                                                "nullable": true
                                                            },
                                                            "to": {
                                                                "type": "string"
                                                            },
                                                            "message": {
                                                                "type": "string"
                                                            },
                                                            "message_preview": {
                                                                "type": "string"
                                                            },
                                                            "date_received": {
                                                                "type": "string",
                                                                "format": "date-time"
                                                            },
                                                            "cost": {
                                                                "type": "number"
                                                            }
                                                        }
                                                    }
                                                },
                                                "pagination": {
                                                    "$ref": "#/components/schemas/MessagesPagination"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/messages/{id}/export": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string"
                    },
                    "description": "External `message_ref` string."
                }
            ],
            "get": {
                "summary": "Export message details by reference",
                "description": "Streams a CSV with a `RECIPIENTS` section followed by a `REPLIES` section. Status labels in this CSV are derived from `provider_status` only (recipient status is not consulted).",
                "tags": [
                    "Messages"
                ],
                "responses": {
                    "200": {
                        "description": "CSV file.",
                        "content": {
                            "text/csv": []
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/messages/chat": {
            "get": {
                "summary": "Conversation history (deprecated)",
                "description": "Documented in error: `messages.php` has no handler at this path, so requests fall through the legacy branch and are treated as `GET /messages/{message_ref}` with `message_ref=\"chat\"`, returning 404. Use `GET /chats/history` instead.",
                "tags": [
                    "Messages"
                ],
                "deprecated": true,
                "responses": {
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/mms/slides/{mms_hash}/{display_order}.{ext}": {
            "parameters": [
                {
                    "name": "mms_hash",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "pattern": "^[A-Za-z0-9\\-_~]+$"
                    },
                    "description": "MMS hash that identifies the parent message. Must match `[A-Za-z0-9\\-_~]+`."
                },
                {
                    "name": "display_order",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 0
                    },
                    "description": "Zero-based ordinal of the slide within the MMS message."
                },
                {
                    "name": "ext",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string"
                    },
                    "description": "Filename extension used only for the `Content-Disposition` suggested filename. The actual response `Content-Type` comes from the stored slide metadata."
                }
            ],
            "get": {
                "summary": "Get MMS slide content",
                "tags": [
                    "MMS"
                ],
                "description": "Returns the raw bytes of an MMS slide. The slide is loaded from S3 (via a short-lived presigned URL) or, for incoming MMS, from the original HTTP(S) URL stored on the slide. No authentication is required because access is gated by the unguessable `mms_hash`. Responses are cached for one year (`Cache-Control: public, max-age=31536000, immutable`).",
                "security": [],
                "responses": {
                    "200": {
                        "description": "Binary slide content.",
                        "headers": {
                            "Content-Type": {
                                "description": "Stored `content_type` for the slide; defaults to `application/octet-stream` when missing.",
                                "schema": {
                                    "type": "string"
                                }
                            },
                            "Content-Length": {
                                "description": "Byte length of the response body.",
                                "schema": {
                                    "type": "integer"
                                }
                            },
                            "Content-Disposition": {
                                "description": "Always `inline; filename=\"slide_<display_order>[.<ext>]\"`.",
                                "schema": {
                                    "type": "string"
                                }
                            },
                            "Cache-Control": {
                                "schema": {
                                    "type": "string",
                                    "example": "public, max-age=31536000, immutable"
                                }
                            }
                        },
                        "content": {
                            "*/*": {
                                "schema": {
                                    "type": "string",
                                    "format": "binary"
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "405": {
                        "description": "Method not allowed (only GET and HEAD are supported).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    },
                    "502": {
                        "description": "Slide metadata was found but the underlying S3/HTTP fetch failed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    }
                }
            },
            "head": {
                "summary": "Get MMS slide headers",
                "tags": [
                    "MMS"
                ],
                "description": "Returns the same response headers as `GET` (Content-Type, Content-Length from stored `size`, Content-Disposition, Cache-Control) without fetching the underlying content from S3.",
                "security": [],
                "responses": {
                    "200": {
                        "description": "Headers describing the slide; body is empty.",
                        "headers": {
                            "Content-Type": {
                                "description": "Stored `content_type` for the slide; defaults to `application/octet-stream` when missing.",
                                "schema": {
                                    "type": "string"
                                }
                            },
                            "Content-Length": {
                                "description": "Stored slide `size` in bytes (omitted if unknown or negative).",
                                "schema": {
                                    "type": "integer"
                                }
                            },
                            "Content-Disposition": {
                                "description": "Always `inline; filename=\"slide_<display_order>[.<ext>]\"`.",
                                "schema": {
                                    "type": "string"
                                }
                            },
                            "Cache-Control": {
                                "schema": {
                                    "type": "string",
                                    "example": "public, max-age=31536000, immutable"
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "405": {
                        "description": "Method not allowed (only GET and HEAD are supported).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/news": {
            "get": {
                "summary": "List news items",
                "description": "Returns the user-facing news feed shown on the dashboard. Each item is marked `is_new: true` if it was published after the caller's `last_news_viewed` timestamp.",
                "tags": [
                    "News"
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Limit"
                    },
                    {
                        "name": "offset",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "minimum": 0,
                            "default": 0
                        }
                    },
                    {
                        "name": "active_only",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "boolean",
                            "default": true
                        },
                        "description": "When true (default), only include items whose `start_datetime` is in the past and whose `end_datetime` is either null or in the future. Pass `active_only=false` to include expired/future items."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "News items retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "News items retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "items": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "id": {
                                                                "type": "integer"
                                                            },
                                                            "title": {
                                                                "type": "string"
                                                            },
                                                            "body": {
                                                                "type": "string"
                                                            },
                                                            "start_datetime": {
                                                                "type": "string",
                                                                "format": "date-time",
                                                                "description": "ISO 8601 with offset."
                                                            },
                                                            "end_datetime": {
                                                                "type": "string",
                                                                "format": "date-time",
                                                                "nullable": true
                                                            },
                                                            "is_system_status": {
                                                                "type": "integer",
                                                                "description": "0 = regular news, 1 = system status banner."
                                                            },
                                                            "is_new": {
                                                                "type": "boolean",
                                                                "description": "True if posted after the caller's last viewed timestamp."
                                                            },
                                                            "created_at": {
                                                                "type": "string",
                                                                "format": "date-time"
                                                            },
                                                            "updated_at": {
                                                                "type": "string",
                                                                "format": "date-time"
                                                            }
                                                        }
                                                    }
                                                },
                                                "pagination": {
                                                    "type": "object",
                                                    "properties": {
                                                        "total": {
                                                            "type": "integer"
                                                        },
                                                        "limit": {
                                                            "type": "integer"
                                                        },
                                                        "offset": {
                                                            "type": "integer"
                                                        },
                                                        "has_more": {
                                                            "type": "boolean"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/news/viewed": {
            "post": {
                "summary": "Mark news as viewed",
                "description": "Stamps the authenticated user's `last_news_viewed` to the current server time. After this, subsequent `GET /news` responses will mark older items with `is_new: false`.",
                "tags": [
                    "News"
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/numbers": {
            "get": {
                "summary": "List user's incoming numbers",
                "description": "Returns the caller's dedicated incoming numbers. Includes assigned numbers (active/pending/cancelled subscriptions) plus quarantined numbers where the caller is the previous owner. Subaccounts are rejected with 403.",
                "tags": [
                    "Numbers"
                ],
                "responses": {
                    "200": {
                        "description": "Numbers retrieved successfully. `data` is a flat array of number records.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Numbers retrieved successfully"
                                        },
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/IncomingNumber"
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                }
            }
        },
        "/numbers/available": {
            "get": {
                "summary": "List available incoming numbers",
                "description": "Returns up to 10 unassigned numbers the caller can request, filtered by country (defaults to Australia / `61`) and optionally by channel. Sorted by `incoming_number`. Subaccounts are rejected with 403.",
                "tags": [
                    "Numbers"
                ],
                "parameters": [
                    {
                        "name": "channel",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Substring match against the number's `channels` column (e.g. `sms`, `mms`)."
                    },
                    {
                        "name": "country",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "default": "61"
                        },
                        "description": "Country dialling code. Defaults to `61` (Australia)."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Available numbers retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Available numbers retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "numbers": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "incoming_number": {
                                                                "type": "string",
                                                                "description": "The phone number."
                                                            },
                                                            "channels": {
                                                                "type": "string",
                                                                "nullable": true,
                                                                "description": "Supported channels for this number (e.g. `sms`, `sms,mms`)."
                                                            },
                                                            "country": {
                                                                "type": "string",
                                                                "description": "Country dialling code."
                                                            },
                                                            "monthly_fee_ex_gst": {
                                                                "type": "number",
                                                                "description": "Monthly fee in AUD (ex GST). Falls back to the system default when unset on the number."
                                                            },
                                                            "initial_fee_ex_gst": {
                                                                "type": "number",
                                                                "description": "Up-front fee charged on activation (monthly_fee * `initial_months`), ex GST."
                                                            }
                                                        }
                                                    }
                                                },
                                                "initial_months": {
                                                    "type": "integer",
                                                    "description": "Number of months pre-paid on activation (system configurable, default 3)."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                }
            }
        },
        "/numbers/request": {
            "post": {
                "summary": "Request an incoming number",
                "description": "Request an available incoming number. Requires the caller to have a stored payment card and to have made at least one approved purchase (`ccapproval = 1`). If the caller already holds the configured maximum of free numbers (default 3), the request is queued for admin approval and no payment is taken; otherwise payment is processed immediately via the stored card.",
                "tags": [
                    "Numbers"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "incoming_number"
                                ],
                                "properties": {
                                    "incoming_number": {
                                        "type": "string",
                                        "description": "The number to request. Must currently be in `available` status."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Request queued for admin approval (caller is over the free-numbers limit). Returned with HTTP 200.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Number request submitted for approval"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "incoming_number": {
                                                    "type": "string"
                                                },
                                                "status": {
                                                    "type": "string",
                                                    "enum": [
                                                        "pending_approval"
                                                    ]
                                                },
                                                "message": {
                                                    "type": "string",
                                                    "description": "Human-readable note shown to the user about the approval workflow."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "201": {
                        "description": "Number activated immediately after a successful card charge.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Number activated successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "incoming_number": {
                                                    "type": "string"
                                                },
                                                "status": {
                                                    "type": "string",
                                                    "enum": [
                                                        "active"
                                                    ]
                                                },
                                                "invoice_id": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "description": "Payment failed when charging the stored card.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            }
        },
        "/numbers/{number}/cancel": {
            "parameters": [
                {
                    "name": "number",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string"
                    },
                    "description": "The incoming number to cancel (URL-encoded)."
                }
            ],
            "post": {
                "summary": "Cancel number subscription",
                "description": "Cancels a number subscription owned by the caller. `active` subscriptions are flagged as `cancelled` and remain usable until the current paid period ends, then enter a 30-day quarantine. `pending_approval` or `pending_payment` subscriptions are withdrawn immediately and the number returns to `available`.",
                "tags": [
                    "Numbers"
                ],
                "responses": {
                    "200": {
                        "description": "Cancellation accepted.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "description": "Human-readable description of what happened (e.g. quarantine vs. immediate release)."
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "incoming_number": {
                                                    "type": "string"
                                                },
                                                "status": {
                                                    "type": "string",
                                                    "enum": [
                                                        "cancelled",
                                                        "available"
                                                    ],
                                                    "description": "`cancelled` for active subs (kept until renewal date), `available` for pending subs (released immediately)."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/numbers/{number}/undo-cancel": {
            "parameters": [
                {
                    "name": "number",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string"
                    },
                    "description": "The incoming number whose pending cancellation should be undone (URL-encoded)."
                }
            ],
            "post": {
                "summary": "Undo a pending cancellation",
                "description": "Restores a subscription that is in `cancelled` status back to `active`, provided the `next_renewal_date` has not yet passed. Re-queues the renewal reminder if the renewal is more than 24 hours away.",
                "tags": [
                    "Numbers"
                ],
                "responses": {
                    "200": {
                        "description": "Cancellation reversed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Cancellation has been undone. Your number subscription will continue."
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "incoming_number": {
                                                    "type": "string"
                                                },
                                                "status": {
                                                    "type": "string",
                                                    "enum": [
                                                        "active"
                                                    ]
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/numbers/{number}/reactivate": {
            "parameters": [
                {
                    "name": "number",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string"
                    },
                    "description": "The incoming number to reactivate (URL-encoded)."
                }
            ],
            "post": {
                "summary": "Reactivate a quarantined number",
                "description": "Reactivates a number in quarantine. Only the previous owner may call this, and a stored card is required. Charges the initial subscription period up-front (default 3 months) before re-assigning the number.",
                "tags": [
                    "Numbers"
                ],
                "responses": {
                    "200": {
                        "description": "Number reactivated successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Number reactivated successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "incoming_number": {
                                                    "type": "string"
                                                },
                                                "status": {
                                                    "type": "string",
                                                    "enum": [
                                                        "active"
                                                    ]
                                                },
                                                "invoice_id": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "description": "Payment failed when charging the stored card.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/numbers/{number}/pay": {
            "parameters": [
                {
                    "name": "number",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string"
                    },
                    "description": "The incoming number whose pending payment should be processed (URL-encoded)."
                }
            ],
            "post": {
                "summary": "Pay for an approved number",
                "description": "Pays the initial subscription fee for a number that an admin has approved and is now in `pending_payment` status. Requires a stored card. On success the subscription becomes `active`.",
                "tags": [
                    "Numbers"
                ],
                "responses": {
                    "200": {
                        "description": "Payment accepted and number activated.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Number activated successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "incoming_number": {
                                                    "type": "string"
                                                },
                                                "status": {
                                                    "type": "string",
                                                    "enum": [
                                                        "active"
                                                    ]
                                                },
                                                "invoice_id": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "description": "Payment failed when charging the stored card.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorEnvelope"
                                }
                            }
                        }
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/packages": {
            "get": {
                "summary": "Get credit packages",
                "description": "Retrieve all available credit packages for the current user. Returns global packages (available to all users) and any custom packages specific to the user.",
                "tags": [
                    "Billing"
                ],
                "responses": {
                    "200": {
                        "description": "Packages retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Packages retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "packages": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "id": {
                                                                "type": "integer",
                                                                "description": "Package ID",
                                                                "example": 1
                                                            },
                                                            "name": {
                                                                "type": "string",
                                                                "description": "Package name",
                                                                "example": "Package 1"
                                                            },
                                                            "credits": {
                                                                "type": "integer",
                                                                "description": "Number of SMS credits in the package",
                                                                "example": 500
                                                            },
                                                            "price": {
                                                                "type": "number",
                                                                "format": "float",
                                                                "description": "Price excluding GST",
                                                                "example": 45
                                                            },
                                                            "gst": {
                                                                "type": "number",
                                                                "format": "float",
                                                                "description": "GST amount (10%)",
                                                                "example": 4.5
                                                            },
                                                            "price_inc_gst": {
                                                                "type": "number",
                                                                "format": "float",
                                                                "description": "Price including GST",
                                                                "example": 49.5
                                                            },
                                                            "cpc": {
                                                                "type": "number",
                                                                "format": "float",
                                                                "description": "Cost per credit",
                                                                "example": 0.09
                                                            },
                                                            "discount": {
                                                                "type": "integer",
                                                                "description": "Discount percentage",
                                                                "example": 0
                                                            },
                                                            "bonus": {
                                                                "type": "integer",
                                                                "description": "Bonus credits included",
                                                                "example": 0
                                                            },
                                                            "is_custom": {
                                                                "type": "boolean",
                                                                "description": "Whether this is a custom package for the user",
                                                                "example": false
                                                            },
                                                            "notes": {
                                                                "type": "string",
                                                                "nullable": true,
                                                                "description": "Package notes",
                                                                "example": null
                                                            }
                                                        }
                                                    }
                                                },
                                                "count": {
                                                    "type": "integer",
                                                    "description": "Total number of packages",
                                                    "example": 5
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "500": {
                        "$ref": "#/components/responses/ServerError"
                    }
                }
            }
        },
        "/routing": {
            "get": {
                "summary": "List routing rules",
                "description": "Returns the effective account's routing rules in priority order (lowest sort_order first) plus the account default action for traffic that no rule matches.",
                "tags": [
                    "Routing"
                ],
                "responses": {
                    "200": {
                        "description": "Routing rules retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Routing rules retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "rules": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/RoutingRule"
                                                    }
                                                },
                                                "default_action": {
                                                    "type": "string",
                                                    "enum": [
                                                        "allow",
                                                        "block"
                                                    ],
                                                    "description": "Applied to traffic that no rule matches."
                                                },
                                                "editable": {
                                                    "type": "boolean",
                                                    "description": "False when the rules are inherited read-only from the parent account (parent_routing_access = view)."
                                                },
                                                "inherited": {
                                                    "type": "boolean",
                                                    "description": "True when these rules belong to the parent account (parent_routing_access = view or manage)."
                                                },
                                                "access_level": {
                                                    "type": "string",
                                                    "enum": [
                                                        "none",
                                                        "view",
                                                        "manage"
                                                    ],
                                                    "description": "This account's parent_routing_access level."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "post": {
                "summary": "Create routing rule",
                "description": "Creates a routing rule, appended to the end of the priority order. WHEN conditions: country, message type, an optional match_sender_id (omit to match any Sender ID), and sender_status (any / unregistered). THEN action: allow / block / remove / replace. A replacement Sender ID is required for the replace action; it follows the same rules as the /v2/send page (a mobile number up to 11 digits, or an ACMA-valid alphanumeric Sender ID).",
                "tags": [
                    "Routing"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "country",
                                    "action"
                                ],
                                "properties": {
                                    "country": {
                                        "type": "string",
                                        "description": "ISO 3166-1 alpha-2 region code (e.g. AU, NZ), or '*' to match any recipient country.",
                                        "example": "NZ"
                                    },
                                    "message_type": {
                                        "type": "string",
                                        "enum": [
                                            "sms",
                                            "mms",
                                            "both"
                                        ],
                                        "default": "both"
                                    },
                                    "match_sender_id": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "description": "Optional Sender ID match condition. When set, the rule only fires for messages whose original Sender ID equals this value (case-insensitive). Omit or null to match any Sender ID. A mobile number (max 11 digits) or any Sender ID up to 11 characters.",
                                        "example": "MyBrand"
                                    },
                                    "sender_status": {
                                        "type": "string",
                                        "enum": [
                                            "any",
                                            "unregistered"
                                        ],
                                        "default": "any",
                                        "description": "Registration match condition. 'unregistered' fires only for senders that are not an approved pool Sender ID (numeric senders count as registered); 'any' ignores registration."
                                    },
                                    "action": {
                                        "type": "string",
                                        "enum": [
                                            "allow",
                                            "block",
                                            "remove",
                                            "replace"
                                        ]
                                    },
                                    "replacement_sender": {
                                        "type": "string",
                                        "description": "Required for the replace action. A mobile number (max 11 digits) or an ACMA-valid alphanumeric Sender ID, same as the send page.",
                                        "example": "MyBrand"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Routing rule created successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Routing rule created successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "rule_id": {
                                                    "type": "integer",
                                                    "example": 1
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/routing/order": {
            "put": {
                "summary": "Reorder routing rules",
                "description": "Sets the priority order of the account's rules. The request lists rule IDs top-to-bottom; each rule's sort_order is set to its position. First-match evaluation follows this order.",
                "tags": [
                    "Routing"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "order"
                                ],
                                "properties": {
                                    "order": {
                                        "type": "array",
                                        "items": {
                                            "type": "integer"
                                        },
                                        "description": "Rule IDs in the desired top-to-bottom order.",
                                        "example": [
                                            3,
                                            1,
                                            2
                                        ]
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/routing/default": {
            "put": {
                "summary": "Set default action",
                "description": "Sets the account default action applied to traffic that no rule matches: allow (send unchanged) or block (drop).",
                "tags": [
                    "Routing"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "action"
                                ],
                                "properties": {
                                    "action": {
                                        "type": "string",
                                        "enum": [
                                            "allow",
                                            "block"
                                        ]
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Default action updated successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Default action updated successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "default_action": {
                                                    "type": "string",
                                                    "enum": [
                                                        "allow",
                                                        "block"
                                                    ]
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/routing/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Routing rule ID"
                }
            ],
            "put": {
                "summary": "Update routing rule",
                "description": "Updates a routing rule owned by the effective account. Only fields included in the request body are changed; the merged rule is re-validated.",
                "tags": [
                    "Routing"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "country": {
                                        "type": "string"
                                    },
                                    "message_type": {
                                        "type": "string",
                                        "enum": [
                                            "sms",
                                            "mms",
                                            "both"
                                        ]
                                    },
                                    "match_sender_id": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "description": "Optional Sender ID match condition (case-insensitive). Null matches any Sender ID."
                                    },
                                    "sender_status": {
                                        "type": "string",
                                        "enum": [
                                            "any",
                                            "unregistered"
                                        ],
                                        "description": "Registration match condition (any / unregistered)."
                                    },
                                    "action": {
                                        "type": "string",
                                        "enum": [
                                            "allow",
                                            "block",
                                            "remove",
                                            "replace"
                                        ]
                                    },
                                    "replacement_sender": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "patch": {
                "summary": "Update routing rule (alias)",
                "description": "Alias of PUT /routing/{id}.",
                "tags": [
                    "Routing"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "country": {
                                        "type": "string"
                                    },
                                    "message_type": {
                                        "type": "string",
                                        "enum": [
                                            "sms",
                                            "mms",
                                            "both"
                                        ]
                                    },
                                    "match_sender_id": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "description": "Optional Sender ID match condition (case-insensitive). Null matches any Sender ID."
                                    },
                                    "sender_status": {
                                        "type": "string",
                                        "enum": [
                                            "any",
                                            "unregistered"
                                        ],
                                        "description": "Registration match condition (any / unregistered)."
                                    },
                                    "action": {
                                        "type": "string",
                                        "enum": [
                                            "allow",
                                            "block",
                                            "remove",
                                            "replace"
                                        ]
                                    },
                                    "replacement_sender": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "delete": {
                "summary": "Delete routing rule",
                "description": "Deletes a routing rule owned by the effective account.",
                "tags": [
                    "Routing"
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/scheduled": {
            "get": {
                "summary": "List scheduled messages",
                "description": "Returns a paginated list of the caller's scheduled messages, plus aggregate counters by status. Supports filtering by status, scheduled date range, search term, and account scope (own account, all subaccounts, or a specific subaccount). Excludes completed messages older than 3 hours.",
                "tags": [
                    "Scheduled"
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/Limit"
                    },
                    {
                        "$ref": "#/components/parameters/Search"
                    },
                    {
                        "name": "account",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "default": "this"
                        },
                        "description": "Filter by account scope: 'this' for current account only, 'all' for current account and all subaccounts, or a numeric subaccount ID for a specific subaccount."
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "Active",
                                "Scheduled",
                                "Sending",
                                "Completed",
                                "Out of Credit",
                                "Failed",
                                "Paused",
                                "Queued"
                            ]
                        },
                        "description": "Filter by status name. 'Active' excludes Completed and Failed; the others map 1:1 to the stored status code."
                    },
                    {
                        "name": "from",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Earliest scheduled date/time (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS), interpreted in the supplied timezone."
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Latest scheduled date/time (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS), interpreted in the supplied timezone."
                    },
                    {
                        "name": "timezone",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "default": "Australia/Melbourne"
                        },
                        "description": "IANA timezone identifier used to interpret the from/to filters before converting to server time."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Scheduled messages retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Scheduled messages retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "description": "List of scheduled messages on the current page.",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "id": {
                                                                "type": "integer"
                                                            },
                                                            "message": {
                                                                "type": "string"
                                                            },
                                                            "sender": {
                                                                "type": "string",
                                                                "nullable": true
                                                            },
                                                            "scheduled_time": {
                                                                "type": "string",
                                                                "format": "date-time"
                                                            },
                                                            "recipients": {
                                                                "type": "integer",
                                                                "description": "Count of active recipients (direct numbers + contacts + active group members)."
                                                            },
                                                            "inactive_recipients": {
                                                                "type": "integer",
                                                                "description": "Count of inactive group members."
                                                            },
                                                            "duplicates": {
                                                                "type": "integer"
                                                            },
                                                            "invalid_numbers": {
                                                                "type": "integer"
                                                            },
                                                            "delivery_reports": {
                                                                "type": "boolean"
                                                            },
                                                            "status": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "Scheduled",
                                                                    "Recurring",
                                                                    "Sending",
                                                                    "Completed",
                                                                    "Out of Credit",
                                                                    "Failed",
                                                                    "Paused",
                                                                    "Queued",
                                                                    "Unknown"
                                                                ],
                                                                "description": "Human-readable status. 'Recurring' is reported when a scheduled message has an active recurring schedule attached."
                                                            },
                                                            "status_code": {
                                                                "type": "string",
                                                                "nullable": true,
                                                                "description": "Raw `processed` value from the database."
                                                            },
                                                            "provider": {
                                                                "type": "string",
                                                                "nullable": true
                                                            },
                                                            "has_mms": {
                                                                "type": "boolean"
                                                            },
                                                            "mms_images": {
                                                                "type": "string",
                                                                "nullable": true,
                                                                "description": "Comma-separated MMS image IDs (raw column value)."
                                                            },
                                                            "allow_replies": {
                                                                "type": "boolean"
                                                            },
                                                            "auto_optout": {
                                                                "type": "boolean"
                                                            },
                                                            "long_sms": {
                                                                "type": "boolean"
                                                            },
                                                            "queue": {
                                                                "type": "integer"
                                                            },
                                                            "message_id": {
                                                                "type": "integer",
                                                                "nullable": true
                                                            },
                                                            "type": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "SMS",
                                                                    "MMS"
                                                                ]
                                                            },
                                                            "image_urls": {
                                                                "type": "array",
                                                                "description": "Present only when the message has MMS images.",
                                                                "items": {
                                                                    "type": "string"
                                                                }
                                                            },
                                                            "progress": {
                                                                "type": "object",
                                                                "description": "Present only for messages in an active sending status.",
                                                                "properties": {
                                                                    "sent": {
                                                                        "type": "integer"
                                                                    },
                                                                    "failed": {
                                                                        "type": "integer"
                                                                    },
                                                                    "pending": {
                                                                        "type": "integer"
                                                                    },
                                                                    "total": {
                                                                        "type": "integer"
                                                                    },
                                                                    "progress": {
                                                                        "type": "number",
                                                                        "description": "Percentage finished (0-100), one decimal place."
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                },
                                                "pagination": {
                                                    "type": "object",
                                                    "description": "Custom pagination envelope used by this endpoint (does not follow the global `{total, limit, offset, has_more}` shape).",
                                                    "properties": {
                                                        "current_page": {
                                                            "type": "integer"
                                                        },
                                                        "total_pages": {
                                                            "type": "integer"
                                                        },
                                                        "total_messages": {
                                                            "type": "integer"
                                                        },
                                                        "per_page": {
                                                            "type": "integer"
                                                        },
                                                        "has_next": {
                                                            "type": "boolean"
                                                        },
                                                        "has_previous": {
                                                            "type": "boolean"
                                                        },
                                                        "from": {
                                                            "type": "integer",
                                                            "description": "1-based index of the first row on this page (0 when empty)."
                                                        },
                                                        "to": {
                                                            "type": "integer",
                                                            "description": "1-based index of the last row on this page (0 when empty)."
                                                        }
                                                    }
                                                },
                                                "statistics": {
                                                    "type": "object",
                                                    "description": "Counters across the caller's scope, ignoring status/from/to/search filters but excluding completed messages older than 3 hours.",
                                                    "properties": {
                                                        "total": {
                                                            "type": "integer"
                                                        },
                                                        "scheduled": {
                                                            "type": "integer"
                                                        },
                                                        "recurring": {
                                                            "type": "integer"
                                                        },
                                                        "sending": {
                                                            "type": "integer"
                                                        },
                                                        "completed": {
                                                            "type": "integer"
                                                        },
                                                        "failed": {
                                                            "type": "integer",
                                                            "description": "Sum of Failed and Out of Credit."
                                                        },
                                                        "queued": {
                                                            "type": "integer"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/scheduled/detail/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Scheduled message ID"
                }
            ],
            "get": {
                "summary": "Get scheduled message detail",
                "description": "Returns the full scheduled message record plus recipient counts and, if attached, the active recurring schedule. For paused messages with sent occurrences the recurring `rrule` is rewritten to exclude already-sent occurrences.",
                "tags": [
                    "Scheduled"
                ],
                "responses": {
                    "200": {
                        "description": "Scheduled message details retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Scheduled message details retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "integer"
                                                },
                                                "message": {
                                                    "type": "string"
                                                },
                                                "sender": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "scheduled_time": {
                                                    "type": "string",
                                                    "format": "date-time"
                                                },
                                                "recipients": {
                                                    "type": "integer",
                                                    "description": "Count of active recipients across direct numbers, contacts, and active group members."
                                                },
                                                "inactive_recipients": {
                                                    "type": "integer",
                                                    "description": "Count of inactive group members."
                                                },
                                                "duplicates": {
                                                    "type": "integer"
                                                },
                                                "invalid_numbers": {
                                                    "type": "integer"
                                                },
                                                "delivery_tracking": {
                                                    "type": "boolean"
                                                },
                                                "status": {
                                                    "type": "string",
                                                    "enum": [
                                                        "Scheduled",
                                                        "Sending",
                                                        "Completed",
                                                        "Out of Credit",
                                                        "Failed",
                                                        "Paused",
                                                        "Queued",
                                                        "Unknown"
                                                    ]
                                                },
                                                "status_code": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "provider": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "has_mms": {
                                                    "type": "boolean"
                                                },
                                                "mms_images": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "allow_replies": {
                                                    "type": "boolean"
                                                },
                                                "auto_optout": {
                                                    "type": "boolean"
                                                },
                                                "allow_long_sms": {
                                                    "type": "boolean"
                                                },
                                                "queue": {
                                                    "type": "integer"
                                                },
                                                "message_id": {
                                                    "type": "integer",
                                                    "nullable": true
                                                },
                                                "sms_origin": {
                                                    "type": "string",
                                                    "nullable": true
                                                },
                                                "shorten_urls": {
                                                    "type": "boolean",
                                                    "description": "Defaults to true when the underlying column is not set."
                                                },
                                                "custom_sender": {
                                                    "type": "boolean"
                                                },
                                                "message_type": {
                                                    "type": "string",
                                                    "enum": [
                                                        "sms",
                                                        "mms"
                                                    ]
                                                },
                                                "recurring_schedule": {
                                                    "type": "object",
                                                    "description": "Present only when the message has an active (non-cancelled) recurring schedule.",
                                                    "properties": {
                                                        "recurring_schedule_id": {
                                                            "type": "integer"
                                                        },
                                                        "rrule": {
                                                            "type": "string",
                                                            "description": "RFC 5545 RRULE. For paused messages with occurrences already sent, the COUNT is adjusted to exclude past occurrences."
                                                        },
                                                        "occurrences": {
                                                            "type": "integer",
                                                            "description": "Number of occurrences already sent."
                                                        },
                                                        "last_occurrence": {
                                                            "type": "string",
                                                            "format": "date-time",
                                                            "nullable": true
                                                        },
                                                        "next_occurrence": {
                                                            "type": "string",
                                                            "format": "date-time",
                                                            "nullable": true
                                                        },
                                                        "status": {
                                                            "type": "string"
                                                        },
                                                        "timezone": {
                                                            "type": "string"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/scheduled/edit/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Scheduled message ID"
                }
            ],
            "put": {
                "summary": "Edit paused scheduled message",
                "description": "Updates a paused scheduled message and transitions it back to Scheduled. Replaces the recipient list, optionally updates message body, scheduled time, sender ID, and delivery options. Rejects edits that reference contacts or groups outside the caller's currently accessible subaccount scope.",
                "tags": [
                    "Scheduled"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "message",
                                    "scheduled_time",
                                    "recipients"
                                ],
                                "properties": {
                                    "message": {
                                        "type": "string"
                                    },
                                    "scheduled_time": {
                                        "type": "string",
                                        "format": "date-time"
                                    },
                                    "sender_id": {
                                        "type": "string",
                                        "description": "Sender ID written to the `sender` column."
                                    },
                                    "recipients": {
                                        "type": "array",
                                        "description": "Recipient list. Each item is either a typed object `{type, id|value}` or a bare phone number string.",
                                        "items": {
                                            "oneOf": [
                                                {
                                                    "type": "object",
                                                    "required": [
                                                        "type"
                                                    ],
                                                    "properties": {
                                                        "type": {
                                                            "type": "string",
                                                            "enum": [
                                                                "contact",
                                                                "group",
                                                                "number"
                                                            ]
                                                        },
                                                        "id": {
                                                            "type": "integer",
                                                            "description": "Required when type is 'contact' or 'group'."
                                                        },
                                                        "value": {
                                                            "type": "string",
                                                            "description": "Phone number; used when type is 'number'."
                                                        }
                                                    }
                                                },
                                                {
                                                    "type": "string",
                                                    "description": "Phone number or `c_<id>` / `g_<id>` prefixed contact/group reference."
                                                },
                                                {
                                                    "type": "integer",
                                                    "description": "Bare contact ID."
                                                }
                                            ]
                                        }
                                    },
                                    "options": {
                                        "type": "object",
                                        "properties": {
                                            "delivery_tracking": {
                                                "type": "boolean",
                                                "description": "Maps to `delivery_reports` ('Y'/'N')."
                                            },
                                            "allow_replies": {
                                                "type": "boolean",
                                                "description": "Combined with `auto_optout` to compute the `allowreplies` integer (0=inactive, 1=replies only, 2=replies + SMS opt-out, 3=web opt-out only). If only one of the two flags is supplied in the update, the other is preserved from the existing stored value."
                                            },
                                            "auto_optout": {
                                                "type": "boolean",
                                                "description": "Combined with `allow_replies` to compute the `allowreplies` integer (see above). Persisted on edit."
                                            },
                                            "allow_long_sms": {
                                                "type": "boolean",
                                                "description": "Maps to `longsms` (1/0)."
                                            }
                                        },
                                        "additionalProperties": false
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Scheduled message updated successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Scheduled message updated successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message_id": {
                                                    "type": "integer"
                                                },
                                                "status": {
                                                    "type": "string",
                                                    "example": "Scheduled"
                                                },
                                                "recipients_count": {
                                                    "type": "integer",
                                                    "description": "Number of expanded phone numbers after recipient processing."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/scheduled/pause/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Scheduled message ID"
                }
            ],
            "put": {
                "summary": "Pause scheduled message",
                "description": "Transitions a Scheduled (or already-Paused) message to Paused so it can be edited. Returns success without changes if the message is already paused.",
                "tags": [
                    "Scheduled"
                ],
                "responses": {
                    "200": {
                        "description": "Scheduled message paused.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Scheduled message paused for editing"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message_id": {
                                                    "type": "integer"
                                                },
                                                "status": {
                                                    "type": "string",
                                                    "example": "Paused"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/scheduled/resume/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Scheduled message ID"
                }
            ],
            "put": {
                "summary": "Resume paused scheduled message",
                "description": "Transitions a Paused message back to Scheduled. Returns success without changes if the message is already scheduled.",
                "tags": [
                    "Scheduled"
                ],
                "responses": {
                    "200": {
                        "description": "Paused message resumed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Paused message resumed successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message_id": {
                                                    "type": "integer"
                                                },
                                                "status": {
                                                    "type": "string",
                                                    "example": "Scheduled"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/scheduled/send-now/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Scheduled message ID"
                }
            ],
            "put": {
                "summary": "Send scheduled message now",
                "description": "Brings forward `send_datetime` to NOW() so the next delivery sweep picks the message up immediately. Only works for messages in Scheduled status.",
                "tags": [
                    "Scheduled"
                ],
                "responses": {
                    "200": {
                        "description": "Message scheduled for immediate sending.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Message scheduled for immediate sending"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message_id": {
                                                    "type": "integer"
                                                },
                                                "status": {
                                                    "type": "string",
                                                    "example": "Sending"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/scheduled/recipients/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Scheduled message ID"
                }
            ],
            "get": {
                "summary": "Get scheduled message recipients",
                "description": "Returns the per-recipient breakdown for a scheduled message: direct phone numbers (with contact name when a matching contact exists), contact references, and group references with active/inactive member counts. Falls back to legacy comma-separated `sendto` numbers when present.",
                "tags": [
                    "Scheduled"
                ],
                "responses": {
                    "200": {
                        "description": "Recipients retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Recipients retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "recipients": {
                                                    "type": "array",
                                                    "items": {
                                                        "oneOf": [
                                                            {
                                                                "type": "object",
                                                                "description": "Direct phone number.",
                                                                "properties": {
                                                                    "type": {
                                                                        "type": "string",
                                                                        "enum": [
                                                                            "number"
                                                                        ]
                                                                    },
                                                                    "value": {
                                                                        "type": "string",
                                                                        "description": "Phone number."
                                                                    },
                                                                    "contact_name": {
                                                                        "type": "string",
                                                                        "description": "Present only when a matching contact exists for the caller."
                                                                    }
                                                                }
                                                            },
                                                            {
                                                                "type": "object",
                                                                "description": "Contact reference.",
                                                                "properties": {
                                                                    "type": {
                                                                        "type": "string",
                                                                        "enum": [
                                                                            "contact"
                                                                        ]
                                                                    },
                                                                    "id": {
                                                                        "type": "integer"
                                                                    },
                                                                    "value": {
                                                                        "type": "string",
                                                                        "description": "Contact's phone number; omitted if the contact is no longer accessible."
                                                                    },
                                                                    "contact_name": {
                                                                        "type": "string",
                                                                        "description": "Display name, or 'Contact no longer accessible' placeholder."
                                                                    }
                                                                }
                                                            },
                                                            {
                                                                "type": "object",
                                                                "description": "Group reference.",
                                                                "properties": {
                                                                    "type": {
                                                                        "type": "string",
                                                                        "enum": [
                                                                            "group"
                                                                        ]
                                                                    },
                                                                    "id": {
                                                                        "type": "integer"
                                                                    },
                                                                    "name": {
                                                                        "type": "string",
                                                                        "description": "Group name, or 'Group no longer accessible' placeholder."
                                                                    },
                                                                    "contact_count": {
                                                                        "type": "integer",
                                                                        "description": "Active members; omitted when the group is no longer accessible."
                                                                    },
                                                                    "inactive_contact_count": {
                                                                        "type": "integer",
                                                                        "description": "Inactive members; omitted when the group is no longer accessible."
                                                                    }
                                                                }
                                                            }
                                                        ]
                                                    }
                                                },
                                                "recipients_count": {
                                                    "type": "integer",
                                                    "description": "Total active recipients (direct numbers + contacts + active group members)."
                                                },
                                                "inactive_recipients_count": {
                                                    "type": "integer",
                                                    "description": "Total inactive group members."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/scheduled/recurring-schedule/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Scheduled message ID"
                }
            ],
            "get": {
                "summary": "Get recurring schedule view",
                "tags": [
                    "Scheduled"
                ],
                "description": "Returns a human-readable summary and the next 5 calculated occurrences for the recurring schedule attached to a scheduled message. Only applicable when the message has an active (non-cancelled) recurring schedule.",
                "responses": {
                    "200": {
                        "description": "Recurring schedule retrieved successfully",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Recurring schedule retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "summary": {
                                                    "type": "string",
                                                    "description": "Human-readable summary of the recurring schedule",
                                                    "example": "Repeats daily at 13:00, ends after 2 occurrences"
                                                },
                                                "next_sends": {
                                                    "type": "array",
                                                    "description": "Array of next 5 scheduled occurrence times in ISO8601 format",
                                                    "items": {
                                                        "type": "string",
                                                        "format": "date-time",
                                                        "example": "2025-10-18T13:00:00+11:00"
                                                    },
                                                    "maxItems": 5
                                                },
                                                "occurrences_sent": {
                                                    "type": "integer",
                                                    "description": "Number of occurrences already sent",
                                                    "example": 0,
                                                    "minimum": 0
                                                },
                                                "timezone": {
                                                    "type": "string",
                                                    "description": "Timezone used for the recurring schedule",
                                                    "example": "Australia/Melbourne"
                                                }
                                            },
                                            "required": [
                                                "summary",
                                                "next_sends",
                                                "occurrences_sent",
                                                "timezone"
                                            ]
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    },
                                    "required": [
                                        "success",
                                        "message",
                                        "data"
                                    ]
                                },
                                "example": {
                                    "success": true,
                                    "message": "Recurring schedule retrieved successfully",
                                    "data": {
                                        "summary": "Repeats daily at 13:00, ends after 2 occurrences",
                                        "next_sends": [
                                            "2025-10-18T13:00:00+11:00",
                                            "2025-10-19T13:00:00+11:00"
                                        ],
                                        "occurrences_sent": 0,
                                        "timezone": "Australia/Melbourne"
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "description": "Scheduled message not found or no recurring schedule exists",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": false
                                        },
                                        "error": {
                                            "type": "string",
                                            "example": "No recurring schedule found for this message"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/scheduled/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Scheduled message ID"
                }
            ],
            "delete": {
                "summary": "Cancel scheduled message",
                "description": "Cancels a scheduled message by deleting the `scheduled_messages` row and its `recipients` rows in a transaction. Only messages in Scheduled, Paused, or unprocessed status can be cancelled. Cancellation is authorised solely by ownership; recipient scope is not revalidated, so a subaccount can always cancel its own queued messages.",
                "tags": [
                    "Scheduled"
                ],
                "responses": {
                    "200": {
                        "description": "Scheduled message cancelled successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Scheduled message cancelled successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "nullable": true,
                                            "description": "Always null on success."
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/search": {
            "get": {
                "summary": "Search contacts and groups",
                "description": "Autocomplete-style search across the caller's readable contacts and groups (own + accessible subaccounts). Matches `display_name`, `gsm_number`, and `email` on contacts and `group_name` / `group_description` on groups. Phone-number-like queries are also matched against a normalised form of `gsm_number`. Results from both pools are merged, sorted alphabetically by `name`, and truncated to `limit`.",
                "tags": [
                    "Search"
                ],
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Search term. An empty/missing value short-circuits to an empty result set."
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 20,
                            "default": 10
                        },
                        "description": "Maximum total results returned (contacts + groups combined). Internally the handler queries up to `floor(limit/2)` from each pool before merging and truncating."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Search completed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Search completed"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "results": {
                                                    "type": "array",
                                                    "description": "Merged contact + group matches, sorted case-insensitively by `name`.",
                                                    "items": {
                                                        "oneOf": [
                                                            {
                                                                "type": "object",
                                                                "description": "Contact result.",
                                                                "properties": {
                                                                    "type": {
                                                                        "type": "string",
                                                                        "enum": [
                                                                            "contact"
                                                                        ]
                                                                    },
                                                                    "id": {
                                                                        "type": "integer",
                                                                        "description": "`contacts.contact_id`."
                                                                    },
                                                                    "name": {
                                                                        "type": "string",
                                                                        "description": "`contacts.display_name`."
                                                                    },
                                                                    "gsm_number": {
                                                                        "type": "string",
                                                                        "description": "Stored mobile number (E.164 or otherwise as saved)."
                                                                    },
                                                                    "owner": {
                                                                        "type": "string",
                                                                        "enum": [
                                                                            "self",
                                                                            "parent"
                                                                        ],
                                                                        "description": "`self` if the contact belongs to the calling user, `parent` if it belongs to an accessible subaccount/parent."
                                                                    },
                                                                    "owner_user_id": {
                                                                        "type": "integer",
                                                                        "description": "User ID that owns the contact."
                                                                    },
                                                                    "icon": {
                                                                        "type": "string",
                                                                        "description": "Emoji glyph used by the autocomplete UI (currently the person emoji)."
                                                                    }
                                                                }
                                                            },
                                                            {
                                                                "type": "object",
                                                                "description": "Group result.",
                                                                "properties": {
                                                                    "type": {
                                                                        "type": "string",
                                                                        "enum": [
                                                                            "group"
                                                                        ]
                                                                    },
                                                                    "id": {
                                                                        "type": "integer",
                                                                        "description": "`groups.group_id`."
                                                                    },
                                                                    "name": {
                                                                        "type": "string",
                                                                        "description": "`groups.group_name`."
                                                                    },
                                                                    "description": {
                                                                        "type": "string",
                                                                        "nullable": true,
                                                                        "description": "`groups.group_description`."
                                                                    },
                                                                    "contact_count": {
                                                                        "type": "integer",
                                                                        "description": "Count of active members (`contacts_to_groups.active = 1`) whose contact still exists under the group's owner."
                                                                    },
                                                                    "inactive_contact_count": {
                                                                        "type": "integer",
                                                                        "description": "Count of inactive members (`contacts_to_groups.active = 0`)."
                                                                    },
                                                                    "owner": {
                                                                        "type": "string",
                                                                        "enum": [
                                                                            "self",
                                                                            "parent"
                                                                        ]
                                                                    },
                                                                    "owner_user_id": {
                                                                        "type": "integer"
                                                                    },
                                                                    "icon": {
                                                                        "type": "string",
                                                                        "description": "Emoji glyph used by the autocomplete UI (currently the people emoji)."
                                                                    }
                                                                }
                                                            }
                                                        ]
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/sender_ids": {
            "get": {
                "summary": "List sender IDs",
                "description": "Returns every sender ID belonging to the authenticated user (sorted with numeric/phone-number sender IDs first, then alphabetic). Pass `format=dropdown` for a lightweight payload containing only the sender value, numeric status, status label, icon, colour, and whether sending is currently allowed; the dropdown list additionally includes the account's assigned incoming numbers (own, plus the parent's when sender ID sharing is enabled) rendered in the phone shape and de-duplicated against registered sender IDs. Without `format`, the full ACMA registration record is returned for each row (incoming numbers are not included).",
                "tags": [
                    "Sender IDs"
                ],
                "parameters": [
                    {
                        "name": "format",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "dropdown"
                            ]
                        },
                        "description": "Pass `dropdown` to get the lightweight per-row shape used by send-SMS sender pickers. Omit for the full ACMA record."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Sender IDs retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Sender IDs retrieved successfully"
                                        },
                                        "data": {
                                            "type": "array",
                                            "description": "When `format=dropdown` each item uses the `SenderIdDropdownItem` shape, otherwise the full `SenderIdRecord` shape.",
                                            "items": {
                                                "oneOf": [
                                                    {
                                                        "$ref": "#/components/schemas/SenderIdRecord"
                                                    },
                                                    {
                                                        "$ref": "#/components/schemas/SenderIdDropdownItem"
                                                    }
                                                ]
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            },
            "post": {
                "summary": "Create sender ID",
                "description": "Create a new sender ID registration. All registrations must include ACMA-required fields for the Sender ID Register, including entity details, authorised representative information, and the relationship between the sender ID and the registering entity. Sender IDs cannot start with the '+' symbol; the leading '+' has E164 meaning and is rejected at registration. Sender IDs must contain at least one letter — numeric-only values, including E164 mobile numbers (e.g. `61493415493`) and phone numbers formatted with spaces, dashes, or brackets (e.g. `04 3333 4444`, `(04) 3333 4444`), are rejected. If a row already exists for this `(user_id, senderid)` pair with `status = 0` (Received) it is updated in place; any other status returns a validation error. On success a confirmation email is dispatched via `sendSenderIdNotification(..., 'register')`.",
                "tags": [
                    "Sender IDs"
                ],
                "responses": {
                    "201": {
                        "description": "Sender ID registration submitted successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Sender ID registration submitted successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "sender_id": {
                                                    "type": "integer",
                                                    "description": "Primary key of the newly inserted (or reused) senderids row."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/SenderIdRequest"
                            }
                        }
                    }
                }
            }
        },
        "/sender_ids/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Sender ID record ID (`senderids.senderid_id`)."
                }
            ],
            "get": {
                "summary": "Get sender ID",
                "description": "Returns the full ACMA registration record for a single sender ID owned by the authenticated user. The `auth_rep_first_name`/`auth_rep_last_name` fields are back-filled from the legacy `fullname` column if they are blank in the database.",
                "tags": [
                    "Sender IDs"
                ],
                "responses": {
                    "200": {
                        "description": "Sender ID retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Sender ID retrieved successfully"
                                        },
                                        "data": {
                                            "$ref": "#/components/schemas/SenderIdRecord"
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "put": {
                "summary": "Update sender ID",
                "description": "Update an existing sender ID registration. Edits are permitted only when the application is in status 0 (Received) or status 2 (Queried). Saving a Queried application transitions it back to status 0 (Received) so it is re-queued for review. Only fields present in the request body are updated; sending `\"\"` clears nullable columns but is ignored for NOT NULL columns (`fullname`, `company_number`, `company_name`, `whofor`, `website`, `example`). The legacy aliases `full_name`, `registration_number`, `sending_for`, and `sample_messages` are still accepted. On success a confirmation email is dispatched via `sendSenderIdNotification(..., 'edit')`.",
                "tags": [
                    "Sender IDs"
                ],
                "responses": {
                    "200": {
                        "description": "Sender ID updated successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Sender ID updated successfully"
                                        },
                                        "data": {
                                            "type": "null"
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                },
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/SenderIdRequest"
                            }
                        }
                    }
                }
            },
            "patch": {
                "summary": "Update sender ID (alias of PUT)",
                "description": "Behaves identically to `PUT /sender_ids/{id}` — the handler routes PUT and PATCH through the same code path, so the same edit rules and same field semantics apply.",
                "tags": [
                    "Sender IDs"
                ],
                "responses": {
                    "200": {
                        "description": "Sender ID updated successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Sender ID updated successfully"
                                        },
                                        "data": {
                                            "type": "null"
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                },
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/SenderIdRequest"
                            }
                        }
                    }
                }
            },
            "delete": {
                "summary": "Delete sender ID",
                "description": "Permanently deletes the sender ID record owned by the authenticated user. On success a revocation email is dispatched via `sendSenderIdNotification(..., 'revoke')`.",
                "tags": [
                    "Sender IDs"
                ],
                "responses": {
                    "200": {
                        "description": "Sender ID deleted successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Sender ID deleted successfully"
                                        },
                                        "data": {
                                            "type": "null"
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/sender_ids/list": {
            "get": {
                "summary": "Sender ID status overview (removed)",
                "description": "TODO: doc/code mismatch — there is no handler for `/sender_ids/list`. The dispatcher in `endpoints/sender_ids.php` only routes empty action (list), numeric action (single record), `status`, and `register`; any other GET action returns 404. Marked deprecated until either the handler is added or this operation is removed.",
                "deprecated": true,
                "tags": [
                    "Sender IDs"
                ],
                "responses": {
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/sender_ids/status": {
            "get": {
                "summary": "Check sender ID status",
                "description": "Returns the registration status of a single sender ID for the authenticated user. Mobile numbers (validated by `isValidE164Mobile`) short-circuit to a `Phone Number` response since they do not require ACMA registration. Otherwise the handler looks up the most recent matching `senderids` row and maps the numeric status to a human-readable label, icon, colour, and `allow_sending` flag.",
                "tags": [
                    "Sender IDs"
                ],
                "parameters": [
                    {
                        "name": "senderid",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "maxLength": 15
                        },
                        "description": "Sender ID value to check (max 15 characters)."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Sender ID status retrieved.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Sender ID status retrieved"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "senderid": {
                                                    "type": "string"
                                                },
                                                "status": {
                                                    "type": "integer",
                                                    "nullable": true,
                                                    "enum": [
                                                        null,
                                                        0,
                                                        1,
                                                        2,
                                                        10,
                                                        99
                                                    ],
                                                    "description": "null = Unregistered or Phone Number, 0 = Received, 1 = Forwarded, 2 = Queried, 10 = Approved, 99 = Rejected."
                                                },
                                                "status_text": {
                                                    "type": "string",
                                                    "enum": [
                                                        "Phone Number",
                                                        "Unregistered",
                                                        "Received",
                                                        "Forwarded",
                                                        "Queried",
                                                        "Approved",
                                                        "Rejected",
                                                        "Unknown"
                                                    ]
                                                },
                                                "icon": {
                                                    "type": "string",
                                                    "description": "Emoji icon (phone, warning, stop, tick)."
                                                },
                                                "color": {
                                                    "type": "string",
                                                    "description": "CSS hex colour suggested for status display."
                                                },
                                                "allow_sending": {
                                                    "type": "boolean",
                                                    "description": "Whether the UI should allow sending with this sender ID."
                                                },
                                                "is_phone": {
                                                    "type": "boolean",
                                                    "description": "Only present (and true) when the value is a valid E164 mobile."
                                                },
                                                "message": {
                                                    "type": "string",
                                                    "description": "Human-readable status explanation."
                                                },
                                                "date_submitted": {
                                                    "type": "string",
                                                    "format": "date-time",
                                                    "nullable": true,
                                                    "description": "From `senderids.created`."
                                                },
                                                "date_processed": {
                                                    "type": "string",
                                                    "format": "date-time",
                                                    "nullable": true,
                                                    "description": "From `senderids.approved`."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/sender_ids/suggestions": {
            "get": {
                "summary": "Suggest sender IDs to register",
                "description": "Returns alpha sender IDs the effective account has recently *used but not registered* — custom alpha sender IDs the delivery system overstamped to \"Unverified\" and recorded in the `messages_routed` routing ledger. These are surfaced as one-click suggestions in the Register New Sender ID modal so customers can register overstamped sender IDs without retyping. Criteria: `is_alpha = 1`, `route_result = 'unverified'`, `created` within the last 60 days (a tunable named constant `SENDERID_SUGGESTION_WINDOW_DAYS`), scoped to the effective (read-only) account, and not already present in the `senderids` table for that account (any status). Results are grouped by sender ID and ordered by most recently used first.",
                "tags": [
                    "Sender IDs"
                ],
                "responses": {
                    "200": {
                        "description": "Sender ID suggestions retrieved.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Sender ID suggestions retrieved"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "suggestions": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "senderid": {
                                                                "type": "string",
                                                                "description": "The unregistered alpha sender ID."
                                                            },
                                                            "last_used": {
                                                                "type": "string",
                                                                "format": "date-time",
                                                                "nullable": true,
                                                                "description": "ISO 8601 (with timezone offset) of the most recent use in the window."
                                                            },
                                                            "recipients": {
                                                                "type": "integer",
                                                                "description": "Total recipients sent with this sender ID within the window."
                                                            }
                                                        }
                                                    }
                                                },
                                                "window_days": {
                                                    "type": "integer",
                                                    "example": 60,
                                                    "description": "Lookback window in days used to build the suggestions."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/sender_ids/register": {
            "post": {
                "summary": "Register sender ID (legacy)",
                "description": "Legacy sender ID registration endpoint. Unlike `POST /sender_ids`, this handler uses the older field names (`full_name`, `registration_number`, `sending_for`, `connection`, `primary_uses`, `sample_messages`, `authorization`) and does NOT capture the full ACMA entity, address, or authorised-representative details. New integrations should call `POST /sender_ids` instead. Sender IDs cannot start with the '+' symbol; the leading '+' has E164 meaning and is rejected at registration. Sender IDs must contain at least one letter — numeric-only values, including E164 mobile numbers and phone numbers formatted with spaces, dashes, or brackets, are rejected.",
                "tags": [
                    "Sender IDs"
                ],
                "responses": {
                    "200": {
                        "description": "Sender ID registration submitted successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Sender ID registration submitted successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "senderid_id": {
                                                    "type": "integer"
                                                },
                                                "senderid": {
                                                    "type": "string"
                                                },
                                                "status": {
                                                    "type": "integer",
                                                    "enum": [
                                                        0
                                                    ],
                                                    "description": "Always 0 (Received) on creation."
                                                },
                                                "status_text": {
                                                    "type": "string",
                                                    "example": "Received"
                                                },
                                                "icon": {
                                                    "type": "string",
                                                    "example": "⚠️"
                                                },
                                                "color": {
                                                    "type": "string",
                                                    "example": "#ffc107"
                                                },
                                                "allow_sending": {
                                                    "type": "boolean",
                                                    "example": true
                                                },
                                                "message": {
                                                    "type": "string"
                                                },
                                                "created": {
                                                    "type": "string",
                                                    "format": "date-time",
                                                    "description": "ISO 8601 with timezone offset; server-side creation timestamp."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "409": {
                        "description": "Sender ID already registered by this user.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorResponse"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "senderid",
                                    "full_name",
                                    "registration_number",
                                    "company_name",
                                    "sending_for",
                                    "connection",
                                    "primary_uses",
                                    "sample_messages",
                                    "authorization"
                                ],
                                "properties": {
                                    "senderid": {
                                        "type": "string",
                                        "maxLength": 11,
                                        "description": "ACMA-compliant sender ID. Cannot start with `+`."
                                    },
                                    "full_name": {
                                        "type": "string",
                                        "maxLength": 64
                                    },
                                    "registration_number": {
                                        "type": "string",
                                        "maxLength": 16,
                                        "description": "ABN/ACN or other entity registration number."
                                    },
                                    "company_name": {
                                        "type": "string",
                                        "maxLength": 64
                                    },
                                    "sending_for": {
                                        "type": "string",
                                        "maxLength": 10,
                                        "description": "Typically `YOURS` or `OTHER`."
                                    },
                                    "connection": {
                                        "oneOf": [
                                            {
                                                "type": "string"
                                            },
                                            {
                                                "type": "array",
                                                "items": {
                                                    "type": "string"
                                                }
                                            }
                                        ],
                                        "description": "Business connection options. Arrays are comma-joined; combined length must be 64 chars or fewer."
                                    },
                                    "primary_uses": {
                                        "oneOf": [
                                            {
                                                "type": "string"
                                            },
                                            {
                                                "type": "array",
                                                "items": {
                                                    "type": "string"
                                                }
                                            }
                                        ],
                                        "description": "Primary use selections. Arrays are comma-joined; combined length must be 64 chars or fewer."
                                    },
                                    "sample_messages": {
                                        "type": "string",
                                        "maxLength": 1024
                                    },
                                    "authorization": {
                                        "type": "string",
                                        "enum": [
                                            "yes",
                                            "no"
                                        ],
                                        "description": "`yes` sets `authority = 1`, anything else sets it to 0."
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/sms": {
            "post": {
                "summary": "Send SMS",
                "tags": [
                    "SMS"
                ],
                "description": "Send an SMS or MMS immediately or queue scheduling instructions. Returns message reference, segment count, encoding, and cost breakdown. Segment calculations account for opt-out suffix overhead and use UTF-16 code unit counting for UCS-2 (Unicode) messages — emoji and characters above U+FFFF count as 2 units. Set `streaming: true` to receive Server-Sent Events with progress updates instead of a single JSON response.",
                "responses": {
                    "200": {
                        "description": "Message queued or scheduled successfully. When `streaming=true`, the response is an `text/event-stream` of `progress`, `error`, and `complete` events; the `complete` event payload carries the same `data` object documented below.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "SMS queued for delivery successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message_ref": {
                                                    "type": "string",
                                                    "description": "Unique message reference ID (numeric string returned by scheduleMessage)."
                                                },
                                                "sender_id": {
                                                    "type": "string",
                                                    "description": "Sender ID used for the message (empty string if none supplied)."
                                                },
                                                "recipients_count": {
                                                    "type": "integer",
                                                    "description": "Number of valid recipients after deduping and removing blocked numbers."
                                                },
                                                "cost_per_recipient": {
                                                    "type": "number",
                                                    "description": "Credit cost per recipient (includes segment multiplier, delivery tracking, and image costs). Accounts for opt-out suffix overhead when auto_optout is enabled."
                                                },
                                                "total_cost": {
                                                    "type": "number",
                                                    "description": "Total credit cost (cost_per_recipient * recipients_count)."
                                                },
                                                "message_type": {
                                                    "type": "string",
                                                    "enum": [
                                                        "SMS",
                                                        "MMS"
                                                    ]
                                                },
                                                "encoding": {
                                                    "type": "string",
                                                    "enum": [
                                                        "GSM 7-bit",
                                                        "UCS-2",
                                                        "MMS"
                                                    ],
                                                    "description": "Character encoding detected. UCS-2 is used when the message contains non-GSM characters (e.g. emoji, CJK). UCS-2 character counting uses UTF-16 code units where emoji require 2 units (surrogate pair)."
                                                },
                                                "segments": {
                                                    "type": "integer",
                                                    "description": "Number of SMS segments. GSM 7-bit: 1 segment up to 160 chars, then 153 chars per segment. UCS-2: 1 segment up to 70 chars, then 67 chars per segment. Includes opt-out suffix in calculation when auto_optout is enabled. Always 1 for MMS."
                                                },
                                                "status": {
                                                    "type": "string",
                                                    "enum": [
                                                        "queued",
                                                        "scheduled"
                                                    ],
                                                    "description": "Message status — 'queued' for immediate send, 'scheduled' when a future time is specified."
                                                },
                                                "is_first_message": {
                                                    "type": "boolean",
                                                    "description": "True when this is the account's first-ever send (no prior row in messages or the scheduled_messages queue at send time). Used by the web UI to fire a one-off GA4 first_message milestone event."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "description": "Caller lacks `send_messages` permission, attempted to use a sender ID they cannot manage, or the account has been auto-suspended by the blacklist."
                    },
                    "409": {
                        "description": "Unverified-sender confirmation required (only when `is_ui=true`). The send would have its unapproved alphanumeric sender ID replaced with 'Unverified' for Australian recipients. The response body has `success=false` and `data.requires_confirmation=true` with `data.confirmation_type='unverified_sender'`; `data.sender_status` is the sender ID's registration status, which the UI uses to tailor the warning and available actions; the `message` is human-readable warning text. Resubmit the identical payload with `confirm_unverified=true` to send. In streaming mode this is delivered as a `confirm` SSE event with the same `message` and `data`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": false
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "requires_confirmation": {
                                                    "type": "boolean",
                                                    "example": true
                                                },
                                                "confirmation_type": {
                                                    "type": "string",
                                                    "example": "unverified_sender"
                                                },
                                                "sender_status": {
                                                    "type": "string",
                                                    "enum": [
                                                        "unregistered",
                                                        "received",
                                                        "forwarded",
                                                        "queried",
                                                        "rejected",
                                                        "unknown"
                                                    ],
                                                    "description": "Registration status of the sender ID (never 'approved' here — an approved sender is not gated). Mirrors the codes in GET /sender_ids/status."
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "recipients"
                                ],
                                "properties": {
                                    "message": {
                                        "type": "string",
                                        "maxLength": 1600,
                                        "description": "Required for SMS messages. Optional for MMS when images are supplied."
                                    },
                                    "recipients": {
                                        "type": "array",
                                        "items": {
                                            "oneOf": [
                                                {
                                                    "type": "string"
                                                },
                                                {
                                                    "type": "integer"
                                                }
                                            ]
                                        },
                                        "minItems": 1,
                                        "description": "Mix of phone numbers, contact IDs, and group IDs. Resolved by `processRecipientsWithProgress()`."
                                    },
                                    "sender_id": {
                                        "type": "string",
                                        "maxLength": 11,
                                        "description": "Sender ID displayed to recipients. Can be a phone number (max 11 digits) or alphanumeric (2-11 chars). A leading '+' is treated as cosmetic E164 notation and is stripped before processing. Alphanumeric sender IDs must comply with ACMA rules: ASCII 32-126 only, cannot be only numbers, cannot start/end with space or underscore, cannot contain 'Unverified', and cannot be a restricted word (account, alert, anti-fraud, assist, assistance, bank, banking, bill, billing, delivery, help, important, info, information, message, notice, notify, package, password, sale, secure, security, service, support, tax, urgent, verify, verified). Callers without the `manage_sender_ids` permission may only use sender IDs already registered on their account."
                                    },
                                    "message_type": {
                                        "type": "string",
                                        "enum": [
                                            "SMS",
                                            "MMS"
                                        ],
                                        "default": "SMS",
                                        "description": "Set to MMS to deliver multimedia messages via this endpoint. Defaults to SMS."
                                    },
                                    "shorten_urls": {
                                        "type": "boolean",
                                        "description": "When true, URLs in the message body are rewritten through the URL shortener before sending."
                                    },
                                    "delivery_tracking": {
                                        "type": "boolean",
                                        "description": "Enable delivery receipt tracking per recipient."
                                    },
                                    "allow_replies": {
                                        "type": "boolean",
                                        "description": "Enable replies to this message. When combined with auto_optout, uses SMS-based opt-out (19-char overhead). Independent of auto_optout."
                                    },
                                    "allow_long_sms": {
                                        "type": "boolean",
                                        "description": "Allow messages longer than a single segment to be sent as concatenated SMS."
                                    },
                                    "auto_optout": {
                                        "type": "boolean",
                                        "description": "Append opt-out instructions to the delivered message. Decoupled from allow_replies. The opt-out text is not stored in the message field — it is appended per-recipient by the delivery system at send time. The returned segments and cost_per_recipient values account for the opt-out suffix length. When allow_replies=true: SMS-based opt-out ('sms STOP to OptOut', 19-char overhead). When allow_replies=false: web-based opt-out link ('OptOut? s0.au/<hash>', 21-char overhead, unique per recipient)."
                                    },
                                    "is_ui": {
                                        "type": "boolean",
                                        "description": "Set by the web UI to opt in to the unverified-sender confirmation gate. When true, if the send would have its alphanumeric sender ID replaced with 'Unverified' (unregistered alphanumeric sender ID + at least one Australian (+61) recipient), the API responds with HTTP 409 and `data.requires_confirmation=true` instead of sending. The gate also applies the account's own routing rules first (mirroring delivery): if a rule blocks the AU recipients, removes the sender, or replaces it with an approved/numeric sender, the message is not overstamped and no confirmation is required. Resubmit with `confirm_unverified=true` to proceed. API/non-UI callers should omit this and are never gated."
                                    },
                                    "confirm_unverified": {
                                        "type": "boolean",
                                        "description": "Acknowledges the unverified-sender warning (see `is_ui`). When true, the confirmation gate is bypassed and the message is sent even though its alphanumeric sender ID will be replaced with 'Unverified'."
                                    },
                                    "images": {
                                        "type": "array",
                                        "items": {
                                            "oneOf": [
                                                {
                                                    "type": "string",
                                                    "description": "Image URL or base64 data URL."
                                                },
                                                {
                                                    "type": "object",
                                                    "description": "Uploaded file payload (e.g. `{name, size, data}`)."
                                                }
                                            ]
                                        },
                                        "description": "Image attachments. SMS messages produce a t0.au preview link appended to the body; MMS messages upload to S3 and link to an `mms_messages` row. Limit comes from `sms.maxImages` / `mms.maxImages` config (default 9)."
                                    },
                                    "update_scheduled_id": {
                                        "type": "integer",
                                        "description": "ID of existing scheduled message to update (replaces the scheduled message). The target message must be in the Paused status."
                                    },
                                    "scheduling": {
                                        "type": "object",
                                        "properties": {
                                            "scheduled_time": {
                                                "type": "string",
                                                "format": "date-time",
                                                "description": "Datetime to send message (for one-time scheduled messages)."
                                            },
                                            "start_datetime": {
                                                "type": "string",
                                                "format": "date-time",
                                                "description": "Start datetime for recurring schedules (alternative to scheduled_time)."
                                            },
                                            "timezone": {
                                                "type": "string",
                                                "description": "Timezone for scheduled time (e.g., 'Australia/Melbourne').",
                                                "default": "Australia/Melbourne"
                                            },
                                            "rrule": {
                                                "type": "string",
                                                "description": "iCalendar RRULE string for recurring schedules (e.g., 'FREQ=DAILY;COUNT=5'). Preferred over the legacy `recurring` object."
                                            },
                                            "recurring": {
                                                "type": "object",
                                                "description": "Legacy object format for recurring schedules (use rrule instead). Compiled into an RRULE server-side.",
                                                "properties": {
                                                    "frequency": {
                                                        "type": "string",
                                                        "enum": [
                                                            "daily",
                                                            "weekly",
                                                            "monthly",
                                                            "yearly"
                                                        ],
                                                        "description": "Recurrence frequency."
                                                    },
                                                    "interval": {
                                                        "type": "integer",
                                                        "minimum": 1,
                                                        "maximum": 99,
                                                        "default": 1,
                                                        "description": "Interval between occurrences."
                                                    },
                                                    "days_of_week": {
                                                        "type": "array",
                                                        "items": {
                                                            "type": "string",
                                                            "enum": [
                                                                "MO",
                                                                "TU",
                                                                "WE",
                                                                "TH",
                                                                "FR",
                                                                "SA",
                                                                "SU"
                                                            ]
                                                        },
                                                        "description": "Days of week for weekly recurrence."
                                                    },
                                                    "day_of_month": {
                                                        "type": "integer",
                                                        "minimum": 1,
                                                        "maximum": 31,
                                                        "description": "Day of month for monthly recurrence."
                                                    },
                                                    "month_of_year": {
                                                        "type": "integer",
                                                        "minimum": 1,
                                                        "maximum": 12,
                                                        "description": "Month of year for yearly recurrence."
                                                    },
                                                    "end_type": {
                                                        "type": "string",
                                                        "enum": [
                                                            "never",
                                                            "after_occurrences",
                                                            "on_date"
                                                        ],
                                                        "default": "never",
                                                        "description": "How the recurrence should end."
                                                    },
                                                    "end_after_occurrences": {
                                                        "type": "integer",
                                                        "minimum": 1,
                                                        "description": "Number of occurrences before ending (required when end_type is 'after_occurrences')."
                                                    },
                                                    "end_date": {
                                                        "type": "string",
                                                        "format": "date-time",
                                                        "description": "End date for recurrence (required when end_type is 'on_date')."
                                                    }
                                                },
                                                "required": [
                                                    "frequency"
                                                ]
                                            }
                                        }
                                    },
                                    "streaming": {
                                        "type": "boolean",
                                        "default": false,
                                        "description": "When true, returns a Server-Sent Events (SSE) stream with progress updates during large send operations. Useful for sends with many recipients to show real-time progress. The final `complete` event payload matches the standard JSON response data."
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/sms/send": {
            "post": {
                "summary": "Send SMS (alias)",
                "tags": [
                    "SMS"
                ],
                "description": "Alias for `POST /sms`. The request body and response shape are identical — see `POST /sms` for the full specification.",
                "requestBody": {
                    "$ref": "#/paths/~1sms/post/requestBody"
                },
                "responses": {
                    "200": {
                        "$ref": "#/paths/~1sms/post/responses/200"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/paths/~1sms/post/responses/403"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            }
        },
        "/sms/history": {
            "get": {
                "summary": "SMS history",
                "tags": [
                    "SMS"
                ],
                "description": "Returns the authenticated account's sent SMS/MMS history, newest first. Each item is a denormalised aggregate over `messages` joined to `message_recipients`. The `message` body is truncated via `truncateText()` and `status` is mapped to a human label by `getMessageStatusLabel()`.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/Limit"
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Filter by raw numeric `messages.status` code (0=queued, 1=success, 2=failed, 3=partial_success). The handler matches the raw integer column, not the mapped label."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "SMS history retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "SMS history retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "messages": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "message_ref": {
                                                                "type": "string",
                                                                "description": "Public-facing message reference."
                                                            },
                                                            "message": {
                                                                "type": "string",
                                                                "description": "Message body, truncated to the configured preview length."
                                                            },
                                                            "status": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "Queued",
                                                                    "Success",
                                                                    "Failed",
                                                                    "Unknown"
                                                                ],
                                                                "description": "Mapped status label from `getMessageStatusLabel()`. Codes 1 and 3 both map to `Success`."
                                                            },
                                                            "sender_id": {
                                                                "type": "string",
                                                                "nullable": true,
                                                                "description": "`messages.sender` column. May be empty/null when no sender ID was used."
                                                            },
                                                            "total_recipients": {
                                                                "type": "integer",
                                                                "description": "Stored `messages.recipients` count."
                                                            },
                                                            "sent_count": {
                                                                "type": "integer",
                                                                "description": "Number of recipients with delivery status SUCCESS."
                                                            },
                                                            "date_sent": {
                                                                "type": "string",
                                                                "format": "date-time",
                                                                "description": "`messages.send_datetime` formatted as ISO 8601 with offset."
                                                            }
                                                        }
                                                    }
                                                },
                                                "pagination": {
                                                    "type": "object",
                                                    "properties": {
                                                        "current_page": {
                                                            "type": "integer"
                                                        },
                                                        "per_page": {
                                                            "type": "integer"
                                                        },
                                                        "total": {
                                                            "type": "integer"
                                                        },
                                                        "total_pages": {
                                                            "type": "integer"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/sms/status/{message_ref}": {
            "parameters": [
                {
                    "name": "message_ref",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string"
                    },
                    "description": "Message reference returned by `POST /sms`."
                }
            ],
            "get": {
                "summary": "Check SMS status",
                "tags": [
                    "SMS"
                ],
                "description": "Returns aggregate delivery status for a single sent message, including counts of successful, failed, and pending recipients. Recipient status codes are aggregated from `message_recipients` (1=SUCCESS, 2/3/5=FAILED/INVALID/BLOCKED, 4/9=WAITING/QUEUED).",
                "responses": {
                    "200": {
                        "description": "Message status retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Message status retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "message_ref": {
                                                    "type": "string"
                                                },
                                                "status": {
                                                    "type": "string",
                                                    "enum": [
                                                        "Queued",
                                                        "Success",
                                                        "Failed",
                                                        "Unknown"
                                                    ],
                                                    "description": "Overall message status label from `getMessageStatusLabel()`. Codes 1 and 3 both map to `Success`."
                                                },
                                                "message": {
                                                    "type": "string",
                                                    "description": "The full message body as stored on `messages.message`."
                                                },
                                                "sender_id": {
                                                    "type": "string",
                                                    "nullable": true,
                                                    "description": "`messages.sender`. May be empty/null when no sender ID was used."
                                                },
                                                "total_recipients": {
                                                    "type": "integer"
                                                },
                                                "sent_count": {
                                                    "type": "integer",
                                                    "description": "Recipients with delivery status SUCCESS (1)."
                                                },
                                                "failed_count": {
                                                    "type": "integer",
                                                    "description": "Recipients with delivery status FAILED, INVALID, or BLOCKED (2, 3, 5)."
                                                },
                                                "pending_count": {
                                                    "type": "integer",
                                                    "description": "Recipients with delivery status WAITING or QUEUED (4, 9)."
                                                },
                                                "date_sent": {
                                                    "type": "string",
                                                    "format": "date-time",
                                                    "description": "`messages.send_datetime` formatted as ISO 8601 with offset."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/sms/scheduled/{message_ref}": {
            "parameters": [
                {
                    "name": "message_ref",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string"
                    },
                    "description": "Message reference of the scheduled message to cancel."
                }
            ],
            "delete": {
                "summary": "Cancel scheduled SMS",
                "tags": [
                    "SMS"
                ],
                "description": "Cancels a previously scheduled message. Requires the `manage_scheduled` permission. Only messages currently in a cancellable state (Scheduled or Paused) can be cancelled — cancellation removes the row from `scheduled_messages`.",
                "responses": {
                    "200": {
                        "description": "Scheduled message cancelled successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Scheduled message cancelled successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "nullable": true
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Message exists but is not in a cancellable status."
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/templates": {
            "get": {
                "summary": "List templates",
                "description": "Returns the authenticated user's pretyped message templates. Supports pagination and an optional `search` term that matches the template title or body (case-insensitive `LIKE`).",
                "tags": [
                    "Templates"
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/Limit"
                    },
                    {
                        "$ref": "#/components/parameters/Search"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Template messages retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Template messages retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "messages": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "id": {
                                                                "type": "integer"
                                                            },
                                                            "title": {
                                                                "type": "string"
                                                            },
                                                            "message": {
                                                                "type": "string"
                                                            }
                                                        }
                                                    }
                                                },
                                                "pagination": {
                                                    "type": "object",
                                                    "description": "Page-based pagination (not the standard offset/has_more envelope).",
                                                    "properties": {
                                                        "current_page": {
                                                            "type": "integer"
                                                        },
                                                        "per_page": {
                                                            "type": "integer"
                                                        },
                                                        "total": {
                                                            "type": "integer"
                                                        },
                                                        "total_pages": {
                                                            "type": "integer"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            },
            "post": {
                "summary": "Create template",
                "description": "Creates a new pretyped message template for the authenticated user. Requires the `manage_templates` permission when acting on behalf of another user.",
                "tags": [
                    "Templates"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "title",
                                    "message"
                                ],
                                "properties": {
                                    "title": {
                                        "type": "string",
                                        "description": "Template title (stored in `pt_message_title`)."
                                    },
                                    "message": {
                                        "type": "string",
                                        "description": "Template body (stored in `pt_message`)."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Template message created successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Template message created successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "integer",
                                                    "description": "ID of the newly created template."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            }
        },
        "/templates/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Template ID"
                }
            ],
            "get": {
                "summary": "Get template",
                "description": "Returns a single pretyped message template owned by the authenticated user. Returns 404 if the template does not exist or belongs to another user.",
                "tags": [
                    "Templates"
                ],
                "responses": {
                    "200": {
                        "description": "Template message retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Template message retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "integer"
                                                },
                                                "title": {
                                                    "type": "string"
                                                },
                                                "message": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "put": {
                "summary": "Update template",
                "description": "Updates the title and/or body of a template owned by the authenticated user. The handler also accepts `PATCH` with identical semantics. Empty-string values for a field are ignored. Returns 400 if no fields change or none are provided.",
                "tags": [
                    "Templates"
                ],
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "title": {
                                        "type": "string"
                                    },
                                    "message": {
                                        "type": "string"
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Template message updated successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Template message updated successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "nullable": true
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            },
            "patch": {
                "summary": "Update template (alias)",
                "description": "Alias for `PUT /templates/{id}`. The handler routes both verbs to the same function.",
                "tags": [
                    "Templates"
                ],
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "title": {
                                        "type": "string"
                                    },
                                    "message": {
                                        "type": "string"
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Template message updated successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Template message updated successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "nullable": true
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                }
            },
            "delete": {
                "summary": "Delete template",
                "description": "Deletes a pretyped message template owned by the authenticated user. Returns 404 if the template does not exist or belongs to another user.",
                "tags": [
                    "Templates"
                ],
                "responses": {
                    "200": {
                        "description": "Template message deleted successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Template message deleted successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "nullable": true
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/users": {
            "get": {
                "summary": "Get current user",
                "description": "Alias for `GET /users/me`. Returns the full account record for the authenticated user (or the assumed account if the caller is operating in another account's context).",
                "tags": [
                    "Users"
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/users/me": {
            "get": {
                "summary": "Get current user",
                "description": "Returns the full account record for the authenticated user, including credit balance, parent/sub status, and contact details. Honours assumed-account context.",
                "tags": [
                    "Users"
                ],
                "responses": {
                    "200": {
                        "description": "User information retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "User information retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "user_id": {
                                                    "type": "integer"
                                                },
                                                "name": {
                                                    "type": "string",
                                                    "description": "Display name (users.user_name)."
                                                },
                                                "username": {
                                                    "type": "string"
                                                },
                                                "email": {
                                                    "type": "string",
                                                    "format": "email"
                                                },
                                                "gsm_number": {
                                                    "type": "string",
                                                    "description": "Default sender ID."
                                                },
                                                "credits": {
                                                    "type": "number",
                                                    "description": "Displayable credit balance (parent balance if `uses_parent_credits` is true)."
                                                },
                                                "uses_parent_credits": {
                                                    "type": "boolean"
                                                },
                                                "overdraft": {
                                                    "type": "number"
                                                },
                                                "au_credits": {
                                                    "type": "number"
                                                },
                                                "last_login": {
                                                    "type": "string",
                                                    "format": "date-time",
                                                    "nullable": true
                                                },
                                                "account_status": {
                                                    "type": "string",
                                                    "enum": [
                                                        "unvalidated",
                                                        "active",
                                                        "banned",
                                                        "expired",
                                                        "unknown"
                                                    ]
                                                },
                                                "ccapproval": {
                                                    "type": "integer",
                                                    "enum": [
                                                        0,
                                                        1
                                                    ],
                                                    "description": "Credit card pre-authorization status (0 = requires approval, 1 = auto-approved)."
                                                },
                                                "is_sub_account": {
                                                    "type": "boolean"
                                                },
                                                "parent_user_id": {
                                                    "type": "integer",
                                                    "nullable": true
                                                },
                                                "sub_account_count": {
                                                    "type": "integer"
                                                },
                                                "settings": {
                                                    "type": "object",
                                                    "properties": {
                                                        "country_code": {
                                                            "type": "string"
                                                        },
                                                        "default_sender_id": {
                                                            "type": "string"
                                                        },
                                                        "sms_origin": {
                                                            "type": "string"
                                                        },
                                                        "sms_replies_to": {
                                                            "type": "string"
                                                        },
                                                        "overdraft": {
                                                            "type": "number"
                                                        },
                                                        "sms_reply": {
                                                            "type": "boolean"
                                                        },
                                                        "delivery_tracking": {
                                                            "type": "boolean"
                                                        },
                                                        "long_sms": {
                                                            "type": "boolean"
                                                        },
                                                        "shorten_urls": {
                                                            "type": "boolean"
                                                        }
                                                    }
                                                },
                                                "contact_details": {
                                                    "type": "object",
                                                    "properties": {
                                                        "address": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "address1": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "suburb": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "state": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "postcode": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "country": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "phone": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "fax": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "mobile_number": {
                                                            "type": "string",
                                                            "nullable": true
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "put": {
                "summary": "Update current user",
                "description": "Updates the authenticated user's core fields (`user_name`, `email`, `gsm_number`) and contact-detail fields. Mobile numbers are validated and normalized; state is uppercased; postcode must be 4 digits. Returns `data: null` on success.",
                "tags": [
                    "Users"
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                },
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "user_name": {
                                        "type": "string"
                                    },
                                    "email": {
                                        "type": "string",
                                        "format": "email"
                                    },
                                    "gsm_number": {
                                        "type": "string"
                                    },
                                    "mobile_number": {
                                        "type": "string"
                                    },
                                    "address": {
                                        "type": "string"
                                    },
                                    "address1": {
                                        "type": "string"
                                    },
                                    "suburb": {
                                        "type": "string"
                                    },
                                    "state": {
                                        "type": "string",
                                        "description": "Uppercased server-side."
                                    },
                                    "postcode": {
                                        "type": "string",
                                        "pattern": "^[0-9]{4}$"
                                    },
                                    "country": {
                                        "type": "string"
                                    },
                                    "phone": {
                                        "type": "string"
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                }
            }
        },
        "/users/profile": {
            "get": {
                "summary": "Get profile",
                "description": "Returns the profile summary for the account currently in context (own account or assumed account). Includes contact details and credit/overdraft info.",
                "tags": [
                    "Users"
                ],
                "responses": {
                    "200": {
                        "description": "Profile retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Profile retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "user_id": {
                                                    "type": "integer"
                                                },
                                                "name": {
                                                    "type": "string",
                                                    "description": "Account contact name (users.username)."
                                                },
                                                "company": {
                                                    "type": "string",
                                                    "description": "Company name (users.user_name)."
                                                },
                                                "email": {
                                                    "type": "string",
                                                    "format": "email"
                                                },
                                                "sender_id": {
                                                    "type": "string",
                                                    "description": "Default sender ID (users.gsm_number)."
                                                },
                                                "account_status": {
                                                    "type": "string",
                                                    "enum": [
                                                        "unvalidated",
                                                        "active",
                                                        "banned",
                                                        "expired",
                                                        "unknown"
                                                    ]
                                                },
                                                "credits": {
                                                    "type": "number"
                                                },
                                                "uses_parent_credits": {
                                                    "type": "boolean"
                                                },
                                                "overdraft": {
                                                    "type": "number"
                                                },
                                                "ccapproval": {
                                                    "type": "integer",
                                                    "enum": [
                                                        0,
                                                        1
                                                    ],
                                                    "description": "Credit card pre-authorization status (0 = requires approval, 1 = auto-approved)."
                                                },
                                                "last_login": {
                                                    "type": "string",
                                                    "format": "date-time",
                                                    "nullable": true
                                                },
                                                "contact_details": {
                                                    "type": "object",
                                                    "properties": {
                                                        "address": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "address1": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "suburb": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "state": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "postcode": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "phone": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "mobile_number": {
                                                            "type": "string",
                                                            "nullable": true
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "put": {
                "summary": "Update profile",
                "description": "Updates the in-context account's profile fields. `sender_id` is validated against ACMA rules for alphanumeric IDs or stripped to digits (max 11) for phone-number IDs. Contact fields may be passed at the top level or nested under `contact_details` (top-level wins). Returns `data: null` on success.",
                "tags": [
                    "Users"
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    }
                },
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "description": "Maps to users.username."
                                    },
                                    "company": {
                                        "type": "string",
                                        "description": "Maps to users.user_name."
                                    },
                                    "sender_id": {
                                        "type": "string",
                                        "maxLength": 11,
                                        "description": "Default sender ID for messages. Can be a phone number (max 11 digits) or alphanumeric (2-11 chars). A leading '+' is treated as cosmetic E164 notation and is stripped before processing. Alphanumeric sender IDs must comply with ACMA rules: ASCII 32-126 only, cannot be only numbers, cannot start/end with space or underscore, cannot contain 'Unverified', and cannot be a restricted word (account, alert, anti-fraud, assist, assistance, bank, banking, bill, billing, delivery, help, important, info, information, message, notice, notify, package, password, sale, secure, security, service, support, tax, urgent, verify, verified)."
                                    },
                                    "address": {
                                        "type": "string"
                                    },
                                    "address1": {
                                        "type": "string"
                                    },
                                    "suburb": {
                                        "type": "string"
                                    },
                                    "state": {
                                        "type": "string",
                                        "description": "Uppercased server-side."
                                    },
                                    "postcode": {
                                        "type": "string",
                                        "pattern": "^[0-9]{4}$"
                                    },
                                    "phone": {
                                        "type": "string"
                                    },
                                    "mobile_number": {
                                        "type": "string"
                                    },
                                    "contact_details": {
                                        "type": "object",
                                        "properties": {
                                            "address": {
                                                "type": "string"
                                            },
                                            "address1": {
                                                "type": "string"
                                            },
                                            "suburb": {
                                                "type": "string"
                                            },
                                            "state": {
                                                "type": "string"
                                            },
                                            "postcode": {
                                                "type": "string"
                                            },
                                            "phone": {
                                                "type": "string"
                                            },
                                            "mobile_number": {
                                                "type": "string"
                                            }
                                        },
                                        "additionalProperties": false
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                }
            }
        },
        "/users/credit": {
            "get": {
                "summary": "Get credit balance",
                "description": "Returns the in-context account's current credit balance along with the 10 most recent credit_history entries.",
                "tags": [
                    "Users"
                ],
                "responses": {
                    "200": {
                        "description": "Credit information retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Credit information retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "current_balance": {
                                                    "type": "number"
                                                },
                                                "currency": {
                                                    "type": "string",
                                                    "example": "AUD"
                                                },
                                                "recent_transactions": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "amount": {
                                                                "type": "number",
                                                                "description": "Credit delta for the transaction (credit_history.credits)."
                                                            },
                                                            "description": {
                                                                "type": "string",
                                                                "description": "Transaction origin (credit_history.origin)."
                                                            },
                                                            "date": {
                                                                "type": "string",
                                                                "format": "date-time"
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/users/subaccounts": {
            "get": {
                "summary": "List subaccounts",
                "description": "Returns the calling account's subaccounts (one level deep). Supports search, account-status filtering, and sorting. Each row exposes the displayable credit balance plus the `parent_contact_access` and `parent_blocks_access` flags. Subaccounts cannot call this endpoint.",
                "tags": [
                    "Users"
                ],
                "parameters": [
                    {
                        "name": "page",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "default": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100,
                            "default": 50
                        }
                    },
                    {
                        "name": "search",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Substring match against `user_name` or `email`."
                    },
                    {
                        "name": "account_status",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "unvalidated",
                                "active",
                                "banned",
                                "expired"
                            ]
                        }
                    },
                    {
                        "name": "sort_by",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "user_name",
                                "email",
                                "credits",
                                "last_login"
                            ],
                            "default": "user_name"
                        }
                    },
                    {
                        "name": "sort_order",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "ASC",
                                "DESC"
                            ],
                            "default": "ASC"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Subaccounts retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Subaccounts retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "sub_accounts": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "user_id": {
                                                                "type": "integer"
                                                            },
                                                            "name": {
                                                                "type": "string"
                                                            },
                                                            "username": {
                                                                "type": "string"
                                                            },
                                                            "email": {
                                                                "type": "string",
                                                                "format": "email"
                                                            },
                                                            "sender_id": {
                                                                "type": "string",
                                                                "description": "users.gsm_number"
                                                            },
                                                            "credits": {
                                                                "type": "number",
                                                                "description": "Displayable credit balance — parent's balance if `uses_parent_credits` is true."
                                                            },
                                                            "uses_parent_credits": {
                                                                "type": "boolean"
                                                            },
                                                            "last_login": {
                                                                "type": "string",
                                                                "format": "date-time",
                                                                "nullable": true
                                                            },
                                                            "account_status": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "unvalidated",
                                                                    "active",
                                                                    "banned",
                                                                    "expired",
                                                                    "unknown"
                                                                ]
                                                            },
                                                            "parent_contact_access": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "none",
                                                                    "view",
                                                                    "manage"
                                                                ]
                                                            },
                                                            "parent_blocks_access": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "none",
                                                                    "view",
                                                                    "manage"
                                                                ]
                                                            },
                                                            "parent_senderid_access": {
                                                                "type": "string",
                                                                "enum": [
                                                                    "none",
                                                                    "view"
                                                                ],
                                                                "description": "Subaccount's access to the parent's sender IDs."
                                                            }
                                                        }
                                                    }
                                                },
                                                "pagination": {
                                                    "type": "object",
                                                    "properties": {
                                                        "total": {
                                                            "type": "integer"
                                                        },
                                                        "per_page": {
                                                            "type": "integer"
                                                        },
                                                        "current_page": {
                                                            "type": "integer"
                                                        },
                                                        "total_pages": {
                                                            "type": "integer"
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                }
            }
        },
        "/users/subaccount": {
            "post": {
                "summary": "Create subaccount",
                "description": "Creates a new subaccount under the in-context parent account. Requires `manage_subaccounts` permission. Returns the new `user_id` on success. Subaccounts cannot create subaccounts.",
                "tags": [
                    "Users"
                ],
                "responses": {
                    "201": {
                        "description": "Subaccount created successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "user_id": {
                                                    "type": "integer",
                                                    "description": "The newly created subaccount ID."
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "user_name",
                                    "email",
                                    "password"
                                ],
                                "properties": {
                                    "user_name": {
                                        "type": "string",
                                        "description": "Subaccount display name; also stored as the username."
                                    },
                                    "email": {
                                        "type": "string",
                                        "format": "email"
                                    },
                                    "password": {
                                        "type": "string",
                                        "format": "password",
                                        "minLength": 8
                                    },
                                    "sender_id": {
                                        "type": "string",
                                        "description": "Optional default sender ID. Defaults to the parent's `gsm_number` if omitted."
                                    },
                                    "mobile": {
                                        "type": "string",
                                        "description": "Optional mobile number; validated and normalised when present."
                                    },
                                    "use_parent_credits": {
                                        "type": "boolean",
                                        "description": "If true, the subaccount draws from the parent's credit pool (`credits = -9999999`)."
                                    },
                                    "credits": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Initial credit allocation to deduct from the parent. Ignored when `use_parent_credits` is true."
                                    },
                                    "parent_contact_access": {
                                        "type": "string",
                                        "enum": [
                                            "none",
                                            "view",
                                            "manage"
                                        ],
                                        "default": "none",
                                        "description": "Subaccount's access to the parent's contacts, groups, and custom fields. `none` keeps the parent's data invisible; `view` merges parent records as read-only and allows cloning into the subaccount's pool; `manage` additionally allows editing/deleting parent records and adding to the parent pool."
                                    },
                                    "parent_blocks_access": {
                                        "type": "string",
                                        "enum": [
                                            "none",
                                            "view",
                                            "manage"
                                        ],
                                        "default": "none",
                                        "description": "Subaccount's access to the parent's blocked numbers. Any value except `none` also activates the downward block cascade (parent's blocks apply to the subaccount's outgoing messages)."
                                    },
                                    "parent_senderid_access": {
                                        "type": "string",
                                        "enum": [
                                            "none",
                                            "view"
                                        ],
                                        "default": "view",
                                        "description": "Subaccount's access to the parent's sender IDs. `none` hides parent sender IDs; `view` makes them visible (read-only) in the subaccount's sender ID picker."
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/users/subaccount/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Subaccount ID"
                }
            ],
            "get": {
                "summary": "Get subaccount",
                "description": "Returns a single subaccount owned by the in-context parent. Requires `manage_subaccounts`. Includes contact details and the `parent_contact_access` / `parent_blocks_access` flags.",
                "tags": [
                    "Users"
                ],
                "responses": {
                    "200": {
                        "description": "Subaccount details retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Subaccount details retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "user_id": {
                                                    "type": "integer"
                                                },
                                                "name": {
                                                    "type": "string"
                                                },
                                                "username": {
                                                    "type": "string"
                                                },
                                                "email": {
                                                    "type": "string",
                                                    "format": "email"
                                                },
                                                "sender_id": {
                                                    "type": "string"
                                                },
                                                "credits": {
                                                    "type": "number"
                                                },
                                                "uses_parent_credits": {
                                                    "type": "boolean"
                                                },
                                                "last_login": {
                                                    "type": "string",
                                                    "format": "date-time",
                                                    "nullable": true
                                                },
                                                "account_status": {
                                                    "type": "string",
                                                    "enum": [
                                                        "unvalidated",
                                                        "active",
                                                        "banned",
                                                        "expired",
                                                        "unknown"
                                                    ]
                                                },
                                                "parent_contact_access": {
                                                    "type": "string",
                                                    "enum": [
                                                        "none",
                                                        "view",
                                                        "manage"
                                                    ]
                                                },
                                                "parent_blocks_access": {
                                                    "type": "string",
                                                    "enum": [
                                                        "none",
                                                        "view",
                                                        "manage"
                                                    ]
                                                },
                                                "parent_senderid_access": {
                                                    "type": "string",
                                                    "enum": [
                                                        "none",
                                                        "view"
                                                    ],
                                                    "description": "Subaccount's access to the parent's sender IDs."
                                                },
                                                "contact_details": {
                                                    "type": "object",
                                                    "properties": {
                                                        "address": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "suburb": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "state": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "postcode": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "phone": {
                                                            "type": "string",
                                                            "nullable": true
                                                        },
                                                        "mobile_number": {
                                                            "type": "string",
                                                            "nullable": true
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "put": {
                "summary": "Update subaccount",
                "description": "Updates an owned subaccount. Credit allocation changes are transactional: `use_parent_credits: true` returns any existing balance to the parent and sets `credits = -9999999`; otherwise an explicit `credits` value deducts/refunds the difference against the parent's pool.",
                "tags": [
                    "Users"
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                },
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "user_name": {
                                        "type": "string"
                                    },
                                    "email": {
                                        "type": "string",
                                        "format": "email"
                                    },
                                    "sender_id": {
                                        "type": "string",
                                        "description": "Maps to users.gsm_number."
                                    },
                                    "account_status": {
                                        "type": "string",
                                        "enum": [
                                            "unvalidated",
                                            "active",
                                            "banned",
                                            "expired"
                                        ]
                                    },
                                    "use_parent_credits": {
                                        "type": "boolean",
                                        "description": "If true, switches the subaccount to drawing from the parent's credit pool."
                                    },
                                    "credits": {
                                        "type": "number",
                                        "description": "Explicit credit balance. Difference vs current balance is moved between parent and subaccount."
                                    },
                                    "parent_contact_access": {
                                        "type": "string",
                                        "enum": [
                                            "none",
                                            "view",
                                            "manage"
                                        ],
                                        "description": "Subaccount's access to the parent's contacts, groups, and custom fields."
                                    },
                                    "parent_blocks_access": {
                                        "type": "string",
                                        "enum": [
                                            "none",
                                            "view",
                                            "manage"
                                        ],
                                        "description": "Subaccount's access to the parent's blocked numbers. Any value except `none` also activates the downward block cascade."
                                    },
                                    "parent_senderid_access": {
                                        "type": "string",
                                        "enum": [
                                            "none",
                                            "view"
                                        ],
                                        "description": "Subaccount's access to the parent's sender IDs. `none` hides parent sender IDs; `view` makes them visible (read-only) in the subaccount's sender ID picker."
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                }
            },
            "delete": {
                "summary": "Delete subaccount",
                "description": "Deletes an owned subaccount and its contact-details row. Any positive credit balance is refunded to the parent before deletion. Requires `manage_subaccounts`.",
                "tags": [
                    "Users"
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/users/transfer-credits": {
            "post": {
                "summary": "Transfer credits between accounts",
                "description": "Transfers credits between the parent account and one of its subaccounts, or between two subaccounts of the same parent. Both endpoints must belong to the in-context account family, and neither may be using parent credits. Requires `manage_subaccounts`.",
                "tags": [
                    "Users"
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "from_user",
                                    "to_user_id",
                                    "amount"
                                ],
                                "properties": {
                                    "from_user": {
                                        "type": "integer",
                                        "minimum": 1,
                                        "description": "User ID to transfer credits from (parent or subaccount)."
                                    },
                                    "to_user_id": {
                                        "type": "integer",
                                        "minimum": 1,
                                        "description": "User ID to transfer credits to (parent or subaccount)."
                                    },
                                    "amount": {
                                        "type": "number",
                                        "exclusiveMinimum": 0,
                                        "description": "Number of credits to transfer. Must be greater than zero."
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/users/change-email": {
            "post": {
                "summary": "Request email address change",
                "description": "Initiates an email-change flow for the in-context account. Requires `manage_account` permission and verification of the current password. A verification token is stored in `users.comments` (24h expiry) and a confirmation email is sent to `new_email`.",
                "tags": [
                    "Users"
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "new_email",
                                    "password"
                                ],
                                "properties": {
                                    "new_email": {
                                        "type": "string",
                                        "format": "email"
                                    },
                                    "password": {
                                        "type": "string",
                                        "format": "password",
                                        "description": "Current password of the in-context account."
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/users/password": {
            "put": {
                "summary": "Change password",
                "description": "Changes the password for the in-context account. Requires `manage_account` for assumed accounts. The current password of the target account must be supplied. On success, the user's `token_version` is incremented (invalidating other tokens).",
                "tags": [
                    "Users"
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "current_password",
                                    "new_password"
                                ],
                                "properties": {
                                    "current_password": {
                                        "type": "string",
                                        "format": "password"
                                    },
                                    "new_password": {
                                        "type": "string",
                                        "format": "password",
                                        "minLength": 8
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/users/reset-password/{id}": {
            "put": {
                "summary": "Reset subaccount password",
                "description": "Forcibly sets a new password for an owned subaccount (no current-password check). Requires `manage_subaccounts`. Increments the subaccount's `token_version` to invalidate existing sessions.",
                "tags": [
                    "Users"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer",
                            "minimum": 1
                        },
                        "description": "Subaccount ID"
                    }
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "new_password"
                                ],
                                "properties": {
                                    "new_password": {
                                        "type": "string",
                                        "format": "password",
                                        "minLength": 8
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/webhooks": {
            "get": {
                "summary": "List webhooks",
                "description": "Returns all webhooks owned by the authenticated user (or the effective user when acting on behalf of another account via the permissions layer), newest first.",
                "tags": [
                    "Webhooks"
                ],
                "responses": {
                    "200": {
                        "description": "Webhooks retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Webhooks retrieved successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "webhooks": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Webhook"
                                                    }
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "post": {
                "summary": "Create webhook",
                "description": "Creates a new webhook for receiving real-time notifications. Multiple webhooks can be created per user to route different event types (SMS MO, MMS MO, DLR) to different endpoints.",
                "tags": [
                    "Webhooks"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "url"
                                ],
                                "properties": {
                                    "url": {
                                        "type": "string",
                                        "format": "uri",
                                        "description": "Endpoint URL where webhook POSTs will be sent. Must pass PHP's `FILTER_VALIDATE_URL`.",
                                        "example": "https://webhook.site/3760c8e7-0483-4fa9-b8a3-f3870604623a"
                                    },
                                    "packet_format": {
                                        "type": "string",
                                        "enum": [
                                            "json",
                                            "form"
                                        ],
                                        "default": "json",
                                        "description": "Payload format: `json` (application/json) or `form` (application/x-www-form-urlencoded)."
                                    },
                                    "headers": {
                                        "type": "object",
                                        "description": "Custom HTTP headers to include with webhook requests. May also be supplied as a JSON-encoded string.",
                                        "example": {
                                            "Authorization": "Bearer your-token",
                                            "X-Custom-Header": "value"
                                        }
                                    },
                                    "active": {
                                        "type": "boolean",
                                        "default": true,
                                        "description": "Enable or disable webhook deliveries without deleting the record."
                                    },
                                    "include_sms_mo": {
                                        "type": "boolean",
                                        "default": true,
                                        "description": "Receive webhooks for incoming SMS messages."
                                    },
                                    "include_mms_mo": {
                                        "type": "boolean",
                                        "default": true,
                                        "description": "Receive webhooks for incoming MMS messages."
                                    },
                                    "include_dlr": {
                                        "type": "boolean",
                                        "default": true,
                                        "description": "Receive webhooks for delivery receipts."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Webhook created successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Webhook created successfully"
                                        },
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "webhook_id": {
                                                    "type": "integer",
                                                    "description": "ID of the newly created webhook.",
                                                    "example": 1
                                                }
                                            }
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        },
        "/webhooks/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer",
                        "minimum": 1
                    },
                    "description": "Webhook ID"
                }
            ],
            "get": {
                "summary": "Get webhook",
                "description": "Returns the configuration and delivery stats for a single webhook owned by the authenticated user.",
                "tags": [
                    "Webhooks"
                ],
                "responses": {
                    "200": {
                        "description": "Webhook retrieved successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Webhook retrieved successfully"
                                        },
                                        "data": {
                                            "$ref": "#/components/schemas/Webhook"
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "put": {
                "summary": "Update webhook",
                "description": "Updates an existing webhook configuration. Only fields included in the request body are modified. Webhooks with a non-`ui` `source` (created by an automation platform) cannot be updated through this endpoint and return 403.",
                "tags": [
                    "Webhooks"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "url": {
                                        "type": "string",
                                        "format": "uri",
                                        "description": "Endpoint URL. Must pass `FILTER_VALIDATE_URL`."
                                    },
                                    "packet_format": {
                                        "type": "string",
                                        "enum": [
                                            "json",
                                            "form"
                                        ]
                                    },
                                    "headers": {
                                        "type": [
                                            "object",
                                            "null"
                                        ],
                                        "description": "Custom HTTP headers. May be supplied as an object, a JSON-encoded string, or `null` to clear stored headers."
                                    },
                                    "active": {
                                        "type": "boolean"
                                    },
                                    "include_sms_mo": {
                                        "type": "boolean"
                                    },
                                    "include_mms_mo": {
                                        "type": "boolean"
                                    },
                                    "include_dlr": {
                                        "type": "boolean"
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Webhook updated successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Webhook updated successfully"
                                        },
                                        "data": {
                                            "type": "null"
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "patch": {
                "summary": "Update webhook (alias)",
                "description": "Alias of `PUT /webhooks/{id}`. The handler treats `PATCH` and `PUT` identically: only fields included in the request body are modified.",
                "tags": [
                    "Webhooks"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "url": {
                                        "type": "string",
                                        "format": "uri"
                                    },
                                    "packet_format": {
                                        "type": "string",
                                        "enum": [
                                            "json",
                                            "form"
                                        ]
                                    },
                                    "headers": {
                                        "type": [
                                            "object",
                                            "null"
                                        ]
                                    },
                                    "active": {
                                        "type": "boolean"
                                    },
                                    "include_sms_mo": {
                                        "type": "boolean"
                                    },
                                    "include_mms_mo": {
                                        "type": "boolean"
                                    },
                                    "include_dlr": {
                                        "type": "boolean"
                                    }
                                },
                                "additionalProperties": false
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Success"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationError"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            },
            "delete": {
                "summary": "Delete webhook",
                "description": "Deletes a webhook and stops all future deliveries. Existing queue items are retained for logging. Webhooks with a non-`ui` `source` (managed by an automation platform) cannot be deleted via this endpoint and return 403.",
                "tags": [
                    "Webhooks"
                ],
                "responses": {
                    "200": {
                        "description": "Webhook deleted successfully.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Webhook deleted successfully"
                                        },
                                        "data": {
                                            "type": "null"
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "500": {
                        "$ref": "#/components/responses/InternalError"
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "bearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "bearerFormat": "JWT"
            }
        },
        "responses": {
            "Success": {
                "description": "Request succeeded",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/SuccessEnvelope"
                        }
                    }
                }
            },
            "Created": {
                "description": "Resource created",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/SuccessEnvelope"
                        }
                    }
                }
            },
            "NoContent": {
                "description": "Completed with no additional content"
            },
            "BadRequest": {
                "description": "Bad request",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ErrorEnvelope"
                        }
                    }
                }
            },
            "Unauthorized": {
                "description": "Authentication required",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ErrorEnvelope"
                        }
                    }
                }
            },
            "Forbidden": {
                "description": "Insufficient privileges",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ErrorEnvelope"
                        }
                    }
                }
            },
            "NotFound": {
                "description": "Resource not found",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ErrorEnvelope"
                        }
                    }
                }
            },
            "ValidationError": {
                "description": "Validation failed",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationErrorEnvelope"
                        }
                    }
                }
            },
            "InternalError": {
                "description": "Internal server error",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ErrorEnvelope"
                        }
                    }
                }
            },
            "ServerError": {
                "description": "Internal server error",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ErrorEnvelope"
                        }
                    }
                }
            }
        },
        "parameters": {
            "Page": {
                "name": "page",
                "in": "query",
                "required": false,
                "schema": {
                    "type": "integer",
                    "minimum": 1,
                    "default": 1
                }
            },
            "Limit": {
                "name": "limit",
                "in": "query",
                "required": false,
                "schema": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "default": 20
                }
            },
            "Search": {
                "name": "search",
                "in": "query",
                "required": false,
                "schema": {
                    "type": "string"
                },
                "description": "Search term (supports comma-separated values for bulk filtering)"
            }
        },
        "schemas": {
            "SuccessEnvelope": {
                "type": "object",
                "properties": {
                    "success": {
                        "type": "boolean"
                    },
                    "message": {
                        "type": "string"
                    },
                    "data": {
                        "type": [
                            "object",
                            "array",
                            "string",
                            "number",
                            "boolean",
                            "null"
                        ]
                    },
                    "timestamp": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "ErrorEnvelope": {
                "type": "object",
                "properties": {
                    "success": {
                        "type": "boolean"
                    },
                    "message": {
                        "type": "string"
                    },
                    "data": {
                        "type": [
                            "object",
                            "array",
                            "string",
                            "number",
                            "boolean",
                            "null"
                        ]
                    },
                    "timestamp": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "ValidationErrorEnvelope": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/ErrorEnvelope"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "data": {
                                "type": "object",
                                "additionalProperties": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                ]
            },
            "RoutingRule": {
                "type": "object",
                "properties": {
                    "rule_id": {
                        "type": "integer",
                        "description": "Unique routing rule identifier",
                        "example": 1
                    },
                    "country": {
                        "type": "string",
                        "description": "ISO 3166-1 alpha-2 region code (e.g. AU, NZ), or '*' to match any recipient country.",
                        "example": "NZ"
                    },
                    "message_type": {
                        "type": "string",
                        "enum": [
                            "sms",
                            "mms",
                            "both"
                        ],
                        "description": "Which message type the rule applies to."
                    },
                    "match_sender_id": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Optional Sender ID match condition. When non-empty the rule only fires for messages whose original Sender ID equals this value (case-insensitive); null matches any Sender ID. Country, message type, this condition and sender_status must all match for the rule to fire.",
                        "example": "MyBrand"
                    },
                    "sender_status": {
                        "type": "string",
                        "enum": [
                            "any",
                            "unregistered"
                        ],
                        "description": "Registration match condition. any: fire regardless of the sender's registration. unregistered: only fire when the sender is NOT an approved pool Sender ID (numeric senders count as registered). A registered sender skips an 'unregistered' rule and falls through to the next rule / default.",
                        "default": "any"
                    },
                    "action": {
                        "type": "string",
                        "enum": [
                            "allow",
                            "block",
                            "remove",
                            "replace"
                        ],
                        "description": "Applied once the rule fires (the registration qualifier now lives in sender_status). allow: send unchanged. block: drop the traffic. remove: drop the Sender ID and let delivery select one from the account's number pool (the same way /v2/send does for an empty sender). replace: swap the Sender ID for replacement_sender."
                    },
                    "replacement_sender": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Sender ID to use for the replace action: a mobile number (max 11 digits) or an ACMA-valid alphanumeric Sender ID. Null for allow/block/remove.",
                        "example": "MyBrand"
                    },
                    "sort_order": {
                        "type": "integer",
                        "description": "Priority within the account. Rules are evaluated first-match from the lowest sort_order.",
                        "example": 0
                    },
                    "created": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "updated": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "Webhook": {
                "type": "object",
                "properties": {
                    "webhook_id": {
                        "type": "integer",
                        "description": "Unique webhook identifier",
                        "example": 1
                    },
                    "url": {
                        "type": "string",
                        "format": "uri",
                        "description": "HTTPS endpoint URL where webhook POSTs are sent",
                        "example": "https://webhook.site/3760c8e7-0483-4fa9-b8a3-f3870604623a"
                    },
                    "headers": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "description": "Custom HTTP headers to include with webhook requests",
                        "example": {
                            "Authorization": "Bearer your-token"
                        }
                    },
                    "packet_format": {
                        "type": "string",
                        "enum": [
                            "json",
                            "form"
                        ],
                        "description": "Payload format: json (application/json) or form (application/x-www-form-urlencoded)",
                        "example": "json"
                    },
                    "active": {
                        "type": "boolean",
                        "description": "Whether the webhook is enabled",
                        "example": true
                    },
                    "include_sms_mo": {
                        "type": "boolean",
                        "description": "Receive webhooks for incoming SMS messages",
                        "example": true
                    },
                    "include_mms_mo": {
                        "type": "boolean",
                        "description": "Receive webhooks for incoming MMS messages",
                        "example": true
                    },
                    "include_dlr": {
                        "type": "boolean",
                        "description": "Receive webhooks for delivery receipts",
                        "example": true
                    },
                    "source": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Origin of the webhook. `ui` (or null) for user-created webhooks; any other value (e.g. `zapier`, `make`) means the webhook is managed by an automation platform and cannot be edited or deleted via this API.",
                        "example": "ui"
                    },
                    "managed_by_automation": {
                        "type": "boolean",
                        "description": "True when `source` is set to a non-`ui` value. Automation-managed webhooks always report `include_sms_mo`, `include_mms_mo`, and `include_dlr` as `true` regardless of stored flags, because event filtering is controlled by the upstream subscription.",
                        "example": false
                    },
                    "created": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When webhook was created",
                        "example": "2025-10-18 19:04:41"
                    },
                    "updated": {
                        "type": "string",
                        "format": "date-time",
                        "description": "Last update to webhook configuration",
                        "example": "2025-10-18 19:04:41"
                    },
                    "stats": {
                        "type": "object",
                        "description": "Webhook delivery statistics",
                        "properties": {
                            "total_delivered": {
                                "type": "integer",
                                "description": "Count of successful deliveries (HTTP 2xx)",
                                "example": 0
                            },
                            "total_failed": {
                                "type": "integer",
                                "description": "Count of failed deliveries (after max retries)",
                                "example": 0
                            },
                            "success_rate": {
                                "type": [
                                    "number",
                                    "null"
                                ],
                                "description": "Percentage of successful deliveries",
                                "example": null
                            },
                            "last_delivery": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "format": "date-time",
                                "description": "Timestamp of most recent successful delivery",
                                "example": null
                            }
                        }
                    }
                }
            },
            "WebhookPayloadSMSMO": {
                "type": "object",
                "description": "Webhook payload for incoming SMS messages",
                "properties": {
                    "hook_id": {
                        "type": "integer",
                        "description": "Unique event ID for this transaction",
                        "example": 12421
                    },
                    "event_type": {
                        "type": "string",
                        "enum": [
                            "sms_mo"
                        ],
                        "example": "sms_mo"
                    },
                    "timestamp": {
                        "type": "string",
                        "format": "date-time",
                        "description": "ISO8601 timestamp with timezone",
                        "example": "2025-01-15T10:30:00+11:00"
                    },
                    "from": {
                        "type": "string",
                        "description": "Sender phone number",
                        "example": "61412345678"
                    },
                    "to": {
                        "type": "string",
                        "description": "Recipient phone number",
                        "example": "61481070240"
                    },
                    "message": {
                        "type": "string",
                        "description": "Message text",
                        "example": "Hello, this is a test message"
                    }
                }
            },
            "WebhookPayloadMMSMO": {
                "type": "object",
                "description": "Webhook payload for incoming MMS messages",
                "properties": {
                    "hook_id": {
                        "type": "integer",
                        "description": "Unique event ID for this transaction",
                        "example": 12421
                    },
                    "event_type": {
                        "type": "string",
                        "enum": [
                            "mms_mo"
                        ],
                        "example": "mms_mo"
                    },
                    "timestamp": {
                        "type": "string",
                        "format": "date-time",
                        "example": "2025-01-15T10:35:00+11:00"
                    },
                    "from": {
                        "type": "string",
                        "description": "Sender phone number",
                        "example": "61412345678"
                    },
                    "to": {
                        "type": "string",
                        "description": "Recipient phone number",
                        "example": "61481070240"
                    },
                    "message": {
                        "type": "string",
                        "description": "MMS text content",
                        "example": "Check out this photo"
                    },
                    "images": {
                        "type": "array",
                        "description": "Array of image URLs",
                        "items": {
                            "type": "string",
                            "format": "uri"
                        },
                        "example": [
                            "https://smsmanager.com.au/images/logo1.gif",
                            "https://smsmanager.com.au/images/logo2.png"
                        ]
                    }
                }
            },
            "WebhookPayloadDLR": {
                "type": "object",
                "description": "Webhook payload for delivery receipts",
                "properties": {
                    "hook_id": {
                        "type": "integer",
                        "description": "Unique event ID for this transaction",
                        "example": 12421
                    },
                    "event_type": {
                        "type": "string",
                        "enum": [
                            "dlr"
                        ],
                        "example": "dlr"
                    },
                    "message_ref": {
                        "type": "string",
                        "description": "Message reference ID returned when the message was sent",
                        "example": "111876640000"
                    },
                    "timestamp": {
                        "type": "string",
                        "format": "date-time",
                        "example": "2025-01-15T10:32:00+11:00"
                    },
                    "from": {
                        "type": "string",
                        "description": "Sender ID used for the original message",
                        "example": "YourBrand"
                    },
                    "to": {
                        "type": "string",
                        "description": "Recipient phone number",
                        "example": "61412345678"
                    },
                    "status_code": {
                        "type": "string",
                        "description": "Delivery status code",
                        "example": "Delivered"
                    }
                }
            },
            "AutomationSubscription": {
                "type": "object",
                "description": "Automation platform subscription (Zapier, n8n, Make, etc.)",
                "properties": {
                    "subscription_id": {
                        "type": "integer",
                        "description": "Unique subscription identifier",
                        "example": 1
                    },
                    "webhook_id": {
                        "type": "integer",
                        "description": "Associated webhook ID",
                        "example": 5
                    },
                    "platform": {
                        "type": "string",
                        "description": "Automation platform identifier",
                        "example": "zapier",
                        "enum": [
                            "zapier",
                            "n8n",
                            "make",
                            "pipedream",
                            "manual",
                            "other"
                        ]
                    },
                    "target_url": {
                        "type": "string",
                        "format": "uri",
                        "description": "HTTPS webhook URL where events are POSTed",
                        "example": "https://hooks.zapier.com/hooks/catch/123456/abcdef/"
                    },
                    "event_type": {
                        "type": "string",
                        "description": "Event type that triggers this subscription",
                        "enum": [
                            "sms_mo",
                            "mms_mo",
                            "dlr"
                        ],
                        "example": "sms_mo"
                    },
                    "external_id": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Platform-specific identifier (e.g., Zapier zap_id, n8n workflow_id)",
                        "example": "12345"
                    },
                    "metadata": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "description": "Additional platform-specific data",
                        "example": {
                            "workflow_name": "SMS to Slack",
                            "created_by": "user@example.com"
                        }
                    },
                    "active": {
                        "type": "boolean",
                        "description": "Whether the subscription is active",
                        "example": true
                    },
                    "created": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When subscription was created",
                        "example": "2025-10-19 17:40:15"
                    },
                    "updated": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When the associated webhook was last updated. Falls back to `created` if no webhook update timestamp is available.",
                        "example": "2025-10-19 17:40:15"
                    },
                    "stats": {
                        "type": "object",
                        "description": "Subscription delivery statistics",
                        "properties": {
                            "total_delivered": {
                                "type": "integer",
                                "description": "Count of successful webhook deliveries",
                                "example": 42
                            },
                            "total_failed": {
                                "type": "integer",
                                "description": "Count of failed webhook deliveries",
                                "example": 3
                            },
                            "success_rate": {
                                "type": [
                                    "integer",
                                    "null"
                                ],
                                "description": "Percentage of successful deliveries (0-100), rounded to nearest integer. Null when no delivery attempts have been made.",
                                "example": 93
                            },
                            "last_delivery": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "format": "date-time",
                                "description": "Timestamp of most recent successful delivery",
                                "example": "2025-10-19 18:15:30"
                            }
                        }
                    }
                }
            },
            "BlockedNumber": {
                "type": "object",
                "description": "A blocked phone number that cannot receive messages",
                "properties": {
                    "blocked_number_id": {
                        "type": "integer",
                        "description": "Unique blocked number identifier",
                        "example": 123
                    },
                    "number": {
                        "type": "string",
                        "description": "The blocked phone number",
                        "example": "61412345678"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When the number was blocked (ISO 8601)",
                        "example": "2025-01-15T10:30:00+11:00"
                    },
                    "blocked_by": {
                        "type": "string",
                        "enum": [
                            "user",
                            "optout",
                            "web_optout"
                        ],
                        "description": "How the number was blocked (user=manual, optout=SMS STOP reply, web_optout=web opt-out link)",
                        "example": "optout"
                    },
                    "notes": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Optional notes about why this number is blocked",
                        "example": "Customer requested opt-out"
                    },
                    "owner": {
                        "type": "string",
                        "enum": [
                            "self",
                            "parent"
                        ],
                        "description": "Whether this record is owned by the calling user or by their parent account."
                    },
                    "owner_user_id": {
                        "type": "integer",
                        "description": "The user_id of the actual owner."
                    }
                }
            },
            "Contact": {
                "type": "object",
                "description": "A contact in the address book. Subaccounts with `parent_contact_access` of `view` or `manage` see a merged view of their own contacts and their parent's contacts.",
                "properties": {
                    "contact_id": {
                        "type": "integer",
                        "description": "Unique contact identifier"
                    },
                    "display_name": {
                        "type": "string",
                        "description": "Contact display name"
                    },
                    "gsm_number": {
                        "type": "string",
                        "description": "Mobile phone number in E.164 form"
                    },
                    "email": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "email"
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "is_blocked": {
                        "type": "boolean",
                        "description": "Whether the contact's phone number is currently blocked"
                    },
                    "owner": {
                        "type": "string",
                        "enum": [
                            "self",
                            "parent"
                        ],
                        "description": "Whether this record is owned by the calling user or by their parent account."
                    },
                    "owner_user_id": {
                        "type": "integer",
                        "description": "The user_id of the actual owner."
                    }
                }
            },
            "Group": {
                "type": "object",
                "description": "A contact group. Subaccounts with `parent_contact_access` of `view` or `manage` see a merged view of their own groups and their parent's groups.",
                "properties": {
                    "group_id": {
                        "type": "integer",
                        "description": "Unique group identifier"
                    },
                    "group_name": {
                        "type": "string",
                        "description": "Group name"
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "contact_count": {
                        "type": "integer",
                        "description": "Number of contacts in this group"
                    },
                    "owner": {
                        "type": "string",
                        "enum": [
                            "self",
                            "parent"
                        ],
                        "description": "Whether this record is owned by the calling user or by their parent account."
                    },
                    "owner_user_id": {
                        "type": "integer",
                        "description": "The user_id of the actual owner."
                    }
                }
            },
            "ContactField": {
                "type": "object",
                "description": "A custom contact field definition. Subaccounts with `parent_contact_access` of `view` or `manage` see a merged view of their own field definitions and their parent's.",
                "properties": {
                    "field_id": {
                        "type": "integer",
                        "description": "Unique field identifier"
                    },
                    "field_name": {
                        "type": "string",
                        "description": "Field display name"
                    },
                    "field_type": {
                        "type": "string",
                        "description": "Field type (text, number, date, etc.)"
                    },
                    "owner": {
                        "type": "string",
                        "enum": [
                            "self",
                            "parent"
                        ],
                        "description": "Whether this record is owned by the calling user or by their parent account."
                    },
                    "owner_user_id": {
                        "type": "integer",
                        "description": "The user_id of the actual owner."
                    }
                }
            },
            "Subaccount": {
                "type": "object",
                "description": "A subaccount user record (a user whose `parent_user_id` references the calling user).",
                "properties": {
                    "user_id": {
                        "type": "integer",
                        "description": "Unique user identifier"
                    },
                    "name": {
                        "type": "string",
                        "description": "Subaccount display name"
                    },
                    "email": {
                        "type": "string",
                        "format": "email"
                    },
                    "mobile": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "access_level": {
                        "type": "string"
                    },
                    "credits": {
                        "type": "number",
                        "description": "Available SMS credits"
                    },
                    "parent_contact_access": {
                        "type": "string",
                        "enum": [
                            "none",
                            "view",
                            "manage"
                        ],
                        "default": "none",
                        "description": "Subaccount's access to the parent's contacts, groups, and custom fields. `none` keeps the parent's data invisible; `view` merges parent records as read-only and allows cloning into the subaccount's pool; `manage` additionally allows editing/deleting parent records and adding to the parent pool."
                    },
                    "parent_blocks_access": {
                        "type": "string",
                        "enum": [
                            "none",
                            "view",
                            "manage"
                        ],
                        "default": "none",
                        "description": "Subaccount's access to the parent's blocked numbers. Any value except `none` also activates the downward block cascade (parent's blocks apply to the subaccount's outgoing messages)."
                    },
                    "parent_senderid_access": {
                        "type": "string",
                        "enum": [
                            "none",
                            "view"
                        ],
                        "default": "view",
                        "description": "Subaccount's access to the parent's sender IDs. `none` hides parent sender IDs from the subaccount; `view` makes them visible (read-only) in the subaccount's sender ID picker."
                    }
                }
            },
            "Pagination": {
                "type": "object",
                "description": "Pagination information for list endpoints",
                "properties": {
                    "page": {
                        "type": "integer",
                        "description": "Current page number",
                        "example": 1
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Items per page",
                        "example": 50
                    },
                    "total": {
                        "type": "integer",
                        "description": "Total number of items",
                        "example": 235
                    },
                    "pages": {
                        "type": "integer",
                        "description": "Total number of pages",
                        "example": 5
                    }
                }
            },
            "MessagesPagination": {
                "type": "object",
                "description": "Pagination shape returned by /messages endpoints. The `total_*` field name varies by endpoint (`total_messages`, `total_recipients`, `total_replies`, or `total_count`).",
                "properties": {
                    "current_page": {
                        "type": "integer"
                    },
                    "total_pages": {
                        "type": "integer"
                    },
                    "total_messages": {
                        "type": "integer",
                        "description": "Present on list endpoints (messages, incoming)."
                    },
                    "total_recipients": {
                        "type": "integer",
                        "description": "Present on recipients endpoints."
                    },
                    "total_replies": {
                        "type": "integer",
                        "description": "Present on replies endpoints."
                    },
                    "total_count": {
                        "type": "integer",
                        "description": "Present on `/messages/incoming` alongside `total_messages`."
                    },
                    "per_page": {
                        "type": "integer"
                    },
                    "has_next": {
                        "type": "boolean"
                    },
                    "has_previous": {
                        "type": "boolean"
                    },
                    "from": {
                        "type": "integer",
                        "description": "1-based index of the first item in the current page (0 when empty)."
                    },
                    "to": {
                        "type": "integer",
                        "description": "1-based index of the last item in the current page."
                    }
                }
            },
            "Chat": {
                "type": "object",
                "properties": {
                    "chat_id": {
                        "type": "integer",
                        "description": "Unique chat identifier"
                    },
                    "contact_number": {
                        "type": "string",
                        "description": "Contact phone number"
                    },
                    "contact_name": {
                        "type": "string",
                        "nullable": true,
                        "description": "Contact name if available"
                    },
                    "contact_id": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Contact ID if exists in contacts"
                    },
                    "last_message": {
                        "type": "string",
                        "description": "Preview of the last message"
                    },
                    "last_message_time": {
                        "type": "string",
                        "format": "date-time",
                        "description": "Timestamp of last message"
                    },
                    "unread_count": {
                        "type": "integer",
                        "description": "Number of unread messages"
                    },
                    "is_starred": {
                        "type": "boolean",
                        "description": "Whether chat is starred"
                    },
                    "is_blocked": {
                        "type": "boolean",
                        "description": "Whether contact is blocked"
                    },
                    "archived_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "Timestamp when chat was archived"
                    },
                    "last_read_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "Timestamp of last read message"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When chat was created"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When chat was last updated"
                    }
                }
            },
            "ChatMessage": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Unique message identifier"
                    },
                    "ref": {
                        "type": "string",
                        "description": "Message reference ID"
                    },
                    "direction": {
                        "type": "string",
                        "enum": [
                            "inbound",
                            "outbound"
                        ],
                        "description": "Message direction"
                    },
                    "body": {
                        "type": "string",
                        "description": "Message content"
                    },
                    "timestamp": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When message was sent/received"
                    },
                    "updated": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "When message delivery status was last updated (outbound only)"
                    },
                    "contact_number": {
                        "type": "string",
                        "description": "Contact phone number"
                    },
                    "sender_number": {
                        "type": "string",
                        "description": "Sender ID/phone number"
                    },
                    "contact_name": {
                        "type": "string",
                        "nullable": true,
                        "description": "Contact name if available"
                    },
                    "delivery_status": {
                        "type": "string",
                        "enum": [
                            "Pending",
                            "Queued",
                            "Sent",
                            "Delivered",
                            "Read",
                            "Failed",
                            "Blocked",
                            "Invalid"
                        ],
                        "nullable": true,
                        "description": "Delivery status for outbound messages"
                    },
                    "slides": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "description": "Image URL"
                                },
                                "content_type": {
                                    "type": "string",
                                    "description": "MIME type"
                                }
                            }
                        },
                        "description": "MMS image slides if applicable"
                    }
                }
            },
            "AccountPermissions": {
                "type": "object",
                "description": "Account access permissions for team members",
                "properties": {
                    "send_messages": {
                        "type": "boolean",
                        "description": "Can send SMS and MMS messages"
                    },
                    "view_messages": {
                        "type": "boolean",
                        "description": "Can view message history"
                    },
                    "manage_contacts": {
                        "type": "boolean",
                        "description": "Can add/edit/delete contacts and groups"
                    },
                    "manage_blocked": {
                        "type": "boolean",
                        "description": "Can manage blocked numbers and opt-outs"
                    },
                    "manage_templates": {
                        "type": "boolean",
                        "description": "Can add/edit/delete message templates"
                    },
                    "view_scheduled": {
                        "type": "boolean",
                        "description": "Can view scheduled messages"
                    },
                    "manage_scheduled": {
                        "type": "boolean",
                        "description": "Can create/edit/delete scheduled messages"
                    },
                    "manage_interactive": {
                        "type": "boolean",
                        "description": "Can manage interactive SMS keywords"
                    },
                    "manage_sender_ids": {
                        "type": "boolean",
                        "description": "Can add/edit/delete sender IDs"
                    },
                    "manage_webhooks": {
                        "type": "boolean",
                        "description": "Can add/edit/delete webhooks"
                    },
                    "view_api_keys": {
                        "type": "boolean",
                        "description": "Can view API keys"
                    },
                    "manage_api_keys": {
                        "type": "boolean",
                        "description": "Can create/delete API keys"
                    },
                    "manage_members": {
                        "type": "boolean",
                        "description": "Can invite/manage team members"
                    },
                    "manage_subaccounts": {
                        "type": "boolean",
                        "description": "Can create/edit/delete subaccounts"
                    },
                    "view_billing": {
                        "type": "boolean",
                        "description": "Can view billing history and invoices"
                    },
                    "manage_billing": {
                        "type": "boolean",
                        "description": "Can make purchases and manage billing"
                    },
                    "manage_account": {
                        "type": "boolean",
                        "description": "Can access account settings and change password"
                    }
                }
            },
            "AccountMember": {
                "type": "object",
                "description": "A team member who has access to an account",
                "properties": {
                    "member_id": {
                        "type": "integer",
                        "description": "Unique member record identifier"
                    },
                    "user_id": {
                        "type": "integer",
                        "description": "User ID of the team member"
                    },
                    "user_name": {
                        "type": "string",
                        "description": "Name of the team member"
                    },
                    "email": {
                        "type": "string",
                        "format": "email",
                        "description": "Email address of the team member"
                    },
                    "role": {
                        "type": "string",
                        "enum": [
                            "owner",
                            "guest"
                        ],
                        "description": "Role of the member (owner has all permissions)"
                    },
                    "permissions": {
                        "$ref": "#/components/schemas/AccountPermissions"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When the member was added"
                    }
                }
            },
            "AccountInvitation": {
                "type": "object",
                "description": "A pending invitation to join an account",
                "properties": {
                    "invitation_id": {
                        "type": "integer",
                        "description": "Unique invitation identifier"
                    },
                    "email": {
                        "type": "string",
                        "format": "email",
                        "description": "Email address the invitation was sent to"
                    },
                    "permissions": {
                        "$ref": "#/components/schemas/AccountPermissions"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When the invitation was created"
                    },
                    "expires_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When the invitation expires"
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "pending",
                            "accepted",
                            "expired",
                            "cancelled"
                        ],
                        "description": "Current status of the invitation"
                    }
                }
            },
            "SharedAccount": {
                "type": "object",
                "description": "An account that a user has been granted access to",
                "properties": {
                    "account_user_id": {
                        "type": "integer",
                        "description": "User ID of the account owner"
                    },
                    "owner_name": {
                        "type": "string",
                        "description": "Name of the account owner"
                    },
                    "owner_email": {
                        "type": "string",
                        "format": "email",
                        "description": "Email of the account owner"
                    },
                    "role": {
                        "type": "string",
                        "enum": [
                            "guest"
                        ],
                        "description": "User's role on this account"
                    },
                    "permissions": {
                        "$ref": "#/components/schemas/AccountPermissions"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When access was granted"
                    }
                }
            },
            "MessageHistoryItem": {
                "type": "object",
                "description": "A message in the message history (incoming or outgoing)",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Message ID"
                    },
                    "direction": {
                        "type": "string",
                        "enum": [
                            "incoming",
                            "outgoing"
                        ],
                        "description": "Message direction"
                    },
                    "message": {
                        "type": "string",
                        "description": "Full message text"
                    },
                    "message_preview": {
                        "type": "string",
                        "description": "Truncated message preview (max 150 chars)"
                    },
                    "from": {
                        "type": "string",
                        "description": "Sender phone number (incoming) or sender ID (outgoing)"
                    },
                    "to": {
                        "type": "string",
                        "description": "Recipient phone number"
                    },
                    "contact_name": {
                        "type": "string",
                        "nullable": true,
                        "description": "Contact display name if exists"
                    },
                    "contact_id": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Contact ID if sender exists in contacts (incoming messages only)"
                    },
                    "status": {
                        "type": "string",
                        "description": "Message status (e.g., Reply, Unsolicited, Success, Failed)"
                    },
                    "send_datetime": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When the message was sent/received (ISO8601)"
                    },
                    "recipients": {
                        "type": "integer",
                        "description": "Number of recipients (1 for incoming)"
                    },
                    "total_cost": {
                        "type": "number",
                        "description": "Total credit cost"
                    },
                    "delivery_reports": {
                        "type": "boolean",
                        "description": "Whether delivery reports are available"
                    },
                    "type": {
                        "type": "string",
                        "enum": [
                            "SMS",
                            "MMS"
                        ],
                        "description": "Message type"
                    },
                    "allow_replies": {
                        "type": "boolean",
                        "description": "Whether replies are enabled for this message"
                    },
                    "auto_optout": {
                        "type": "boolean",
                        "description": "Whether auto opt-out is enabled (SMS-based when allow_replies=true, web-based when allow_replies=false)"
                    },
                    "is_overstamped": {
                        "type": "boolean",
                        "description": "Whether the sender ID was overstamped at delivery time (i.e. the original sender ID was unverified and replaced)"
                    },
                    "original_sender": {
                        "type": "string",
                        "nullable": true,
                        "description": "The original sender ID before overstamping; null if not overstamped"
                    },
                    "original_message_id": {
                        "type": "integer",
                        "nullable": true,
                        "description": "ID of the original outgoing message (for replies)"
                    }
                }
            },
            "MessageRecipient": {
                "type": "object",
                "properties": {
                    "recipient": {
                        "type": "string",
                        "description": "Phone number of the recipient"
                    },
                    "status": {
                        "type": "string",
                        "description": "Delivery status of the message"
                    },
                    "cost": {
                        "type": "number",
                        "description": "Credit cost charged for this recipient"
                    },
                    "sender": {
                        "type": "string",
                        "description": "Sender ID used for this message"
                    },
                    "send_datetime": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When the message was sent (ISO8601)"
                    }
                }
            },
            "IncomingNumber": {
                "type": "object",
                "description": "An incoming number subscription as returned by GET /numbers.",
                "properties": {
                    "incoming_number": {
                        "type": "string",
                        "description": "The phone number",
                        "example": "61488844000"
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "pending_approval",
                            "pending_payment",
                            "active",
                            "cancelled",
                            "reserved",
                            "assigned"
                        ],
                        "description": "Display status. `reserved` is shown to customers in place of the internal `quarantine` state. Falls back to the underlying `users_incoming.status` (e.g. `assigned`) when no subscription row exists."
                    },
                    "channels": {
                        "type": "string",
                        "nullable": true,
                        "description": "Supported channels for this number (e.g. `sms`, `sms,mms`)."
                    },
                    "country": {
                        "type": "string",
                        "nullable": true,
                        "description": "Country dialling code."
                    },
                    "subscription_start": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "When the subscription started."
                    },
                    "next_renewal_date": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "Next renewal date."
                    },
                    "cancel_requested_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "When the user requested cancellation, or null if not cancelled."
                    },
                    "monthly_fee": {
                        "type": "number",
                        "description": "Monthly fee in AUD (ex GST). Subscription fee if set, otherwise the number's catalog fee, otherwise the system default.",
                        "example": 10
                    }
                }
            },
            "Card": {
                "type": "object",
                "description": "A stored payment card",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Card record ID (nab_periodic_id)",
                        "example": 1
                    },
                    "last_four": {
                        "type": "string",
                        "description": "Last 4 digits of card number",
                        "example": "1234"
                    },
                    "expiry": {
                        "type": "string",
                        "description": "Card expiry in MM/YY format",
                        "example": "12/25"
                    },
                    "holder_name": {
                        "type": "string",
                        "description": "Cardholder name",
                        "example": "John Smith"
                    },
                    "card_type": {
                        "type": "string",
                        "description": "Detected card brand from BIN range. Amex is detected but rejected on POST.",
                        "enum": [
                            "Visa",
                            "Mastercard",
                            "Amex",
                            "Discover",
                            "Diners",
                            "JCB",
                            "Unknown"
                        ],
                        "example": "Visa"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When the card was added"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When the card was last updated"
                    }
                }
            },
            "SenderIdRequest": {
                "type": "object",
                "description": "Request body for creating or updating a sender ID registration. All ACMA-required fields must be supplied.",
                "required": [
                    "senderid",
                    "whofor",
                    "has_abn",
                    "company_name",
                    "website",
                    "business_address_street_number",
                    "business_address_street",
                    "business_address_city",
                    "business_address_state",
                    "business_address_postcode",
                    "business_address_country",
                    "auth_rep_title",
                    "auth_rep_first_name",
                    "auth_rep_last_name",
                    "auth_rep_email",
                    "auth_rep_mobile",
                    "already_registered_acma",
                    "sender_id_relationship",
                    "authority",
                    "confirm_contact_permission"
                ],
                "properties": {
                    "senderid": {
                        "type": "string",
                        "minLength": 2,
                        "maxLength": 11,
                        "description": "Alphanumeric sender ID. Must comply with ACMA rules: 2-11 characters, ASCII 32-126 only, cannot be only numbers, cannot start/end with space or underscore, cannot contain 'Unverified', and cannot be a restricted word (account, alert, anti-fraud, assist, assistance, bank, banking, bill, billing, delivery, help, important, info, information, message, notice, notify, package, password, sale, secure, security, service, support, tax, urgent, verify, verified)."
                    },
                    "whofor": {
                        "type": "string",
                        "enum": [
                            "YOURS",
                            "OTHER"
                        ],
                        "description": "Ownership type - registering for own use or on behalf of customer"
                    },
                    "has_abn": {
                        "type": "integer",
                        "enum": [
                            0,
                            1
                        ],
                        "description": "Whether entity has an ABN or ACN"
                    },
                    "company_number": {
                        "type": "string",
                        "maxLength": 16,
                        "description": "ABN/ACN number (required when has_abn=1)"
                    },
                    "company_name": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Company/Entity name"
                    },
                    "website": {
                        "type": "string",
                        "maxLength": 255,
                        "description": "Website or social media profile URL"
                    },
                    "business_address_unit": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Business unit/apartment number (optional)"
                    },
                    "business_address_street_number": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Business street number (e.g. '1133-1145')"
                    },
                    "business_address_street": {
                        "type": "string",
                        "maxLength": 128,
                        "description": "Business street name (e.g. 'Malvern Road')"
                    },
                    "business_address_city": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Business suburb"
                    },
                    "business_address_state": {
                        "type": "string",
                        "enum": [
                            "ACT",
                            "NSW",
                            "NT",
                            "QLD",
                            "SA",
                            "TAS",
                            "VIC",
                            "WA"
                        ],
                        "description": "Business state"
                    },
                    "business_address_postcode": {
                        "type": "string",
                        "maxLength": 10,
                        "description": "Business postcode"
                    },
                    "business_address_country": {
                        "type": "string",
                        "maxLength": 64,
                        "default": "Australia",
                        "description": "Business country (defaults to Australia)"
                    },
                    "business_phone": {
                        "type": "string",
                        "maxLength": 20,
                        "description": "Business phone number (optional)"
                    },
                    "auth_rep_title": {
                        "type": "string",
                        "maxLength": 20,
                        "description": "Authorised Representative title (e.g. Mr, Ms, Dr)"
                    },
                    "auth_rep_first_name": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Authorised Representative first name"
                    },
                    "auth_rep_last_name": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Authorised Representative last name"
                    },
                    "auth_rep_email": {
                        "type": "string",
                        "maxLength": 128,
                        "description": "Authorised Representative email address"
                    },
                    "auth_rep_mobile": {
                        "type": "string",
                        "maxLength": 20,
                        "description": "Authorised Representative mobile number in E.164 format"
                    },
                    "already_registered_acma": {
                        "type": "integer",
                        "enum": [
                            0,
                            1
                        ],
                        "description": "Whether the sender ID is already registered with ACMA"
                    },
                    "sender_id_relationship": {
                        "type": "string",
                        "enum": [
                            "BUSINESS_NAME",
                            "COMPANY_NAME",
                            "TRADEMARK",
                            "DOMAIN",
                            "OTHER"
                        ],
                        "description": "The relationship between the sender ID and the registering entity"
                    },
                    "sender_id_relationship_value": {
                        "type": "string",
                        "maxLength": 255,
                        "description": "Description of relationship when sender_id_relationship=OTHER"
                    },
                    "authority": {
                        "type": "boolean",
                        "description": "Confirm authorised to submit this registration on behalf of the entity"
                    },
                    "confirm_contact_permission": {
                        "type": "boolean",
                        "description": "Confirm permission to provide the authorised representative's contact details to ACMA"
                    },
                    "comments": {
                        "type": "string",
                        "description": "Optional additional comments"
                    },
                    "customer_has_abn": {
                        "type": "integer",
                        "enum": [
                            0,
                            1
                        ],
                        "description": "Whether the customer entity has an ABN or ACN (required when whofor=OTHER)"
                    },
                    "customer_company_number": {
                        "type": "string",
                        "maxLength": 20,
                        "description": "Customer ABN/ACN number (required when whofor=OTHER and customer_has_abn=1)"
                    },
                    "customer_company_name": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Customer company/entity name (required when whofor=OTHER)"
                    },
                    "customer_website": {
                        "type": "string",
                        "maxLength": 255,
                        "description": "Customer website or social media profile URL (required when whofor=OTHER)"
                    },
                    "customer_address_unit": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Customer unit/apartment number (optional)"
                    },
                    "customer_address_street_number": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Customer street number (required when whofor=OTHER)"
                    },
                    "customer_address_street": {
                        "type": "string",
                        "maxLength": 128,
                        "description": "Customer street name (required when whofor=OTHER)"
                    },
                    "customer_address_city": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Customer suburb (required when whofor=OTHER)"
                    },
                    "customer_address_state": {
                        "type": "string",
                        "enum": [
                            "ACT",
                            "NSW",
                            "NT",
                            "QLD",
                            "SA",
                            "TAS",
                            "VIC",
                            "WA"
                        ],
                        "description": "Customer state (required when whofor=OTHER)"
                    },
                    "customer_address_postcode": {
                        "type": "string",
                        "maxLength": 10,
                        "description": "Customer postcode (required when whofor=OTHER)"
                    },
                    "customer_address_country": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Customer country"
                    },
                    "customer_business_phone": {
                        "type": "string",
                        "maxLength": 20,
                        "description": "Customer business phone number (optional, used when whofor=OTHER)"
                    },
                    "customer_auth_rep_title": {
                        "type": "string",
                        "maxLength": 20,
                        "description": "Customer authorised representative title (required when whofor=OTHER)"
                    },
                    "customer_auth_rep_first_name": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Customer authorised representative first name (required when whofor=OTHER)"
                    },
                    "customer_auth_rep_last_name": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Customer authorised representative last name (required when whofor=OTHER)"
                    },
                    "customer_auth_rep_email": {
                        "type": "string",
                        "maxLength": 128,
                        "description": "Customer authorised representative email address (required when whofor=OTHER)"
                    },
                    "customer_auth_rep_mobile": {
                        "type": "string",
                        "maxLength": 20,
                        "description": "Customer authorised representative mobile in E.164 format (required when whofor=OTHER)"
                    },
                    "full_name": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Legacy field — full name of registrant (kept for backwards compatibility)"
                    },
                    "connection": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "minItems": 1,
                        "description": "Legacy field — connection types (kept for backwards compatibility)"
                    },
                    "primary_uses": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "minItems": 1,
                        "description": "Legacy field — primary uses for this sender ID (kept for backwards compatibility)"
                    },
                    "sample_messages": {
                        "type": "string",
                        "maxLength": 1024,
                        "description": "Legacy field — sample messages (kept for backwards compatibility)"
                    }
                }
            },
            "SenderIdResponse": {
                "type": "object",
                "description": "Sender ID registration record returned from GET endpoints",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Sender ID record ID"
                    },
                    "senderid": {
                        "type": "string",
                        "description": "The sender ID value"
                    },
                    "status": {
                        "type": "string",
                        "description": "Current registration status (e.g. pending, approved, rejected)"
                    },
                    "owner": {
                        "type": "string",
                        "enum": [
                            "self",
                            "parent"
                        ],
                        "description": "`self` = registered by this account; `parent` = inherited from the parent account."
                    },
                    "is_editable": {
                        "type": "boolean",
                        "description": "Whether the authenticated user can edit or delete this sender ID registration."
                    },
                    "whofor": {
                        "type": "string",
                        "enum": [
                            "YOURS",
                            "OTHER"
                        ],
                        "description": "Ownership type - registered for own use or on behalf of customer"
                    },
                    "has_abn": {
                        "type": "integer",
                        "enum": [
                            0,
                            1
                        ],
                        "description": "Whether entity has an ABN or ACN"
                    },
                    "company_number": {
                        "type": "string",
                        "description": "ABN/ACN number"
                    },
                    "company_name": {
                        "type": "string",
                        "description": "Company/Entity name"
                    },
                    "website": {
                        "type": "string",
                        "description": "Website or social media profile URL"
                    },
                    "business_address_unit": {
                        "type": "string",
                        "description": "Business unit/apartment number"
                    },
                    "business_address_street_number": {
                        "type": "string",
                        "description": "Business street number"
                    },
                    "business_address_street": {
                        "type": "string",
                        "description": "Business street name"
                    },
                    "business_address_city": {
                        "type": "string",
                        "description": "Business suburb"
                    },
                    "business_address_state": {
                        "type": "string",
                        "enum": [
                            "ACT",
                            "NSW",
                            "NT",
                            "QLD",
                            "SA",
                            "TAS",
                            "VIC",
                            "WA"
                        ],
                        "description": "Business state"
                    },
                    "business_address_postcode": {
                        "type": "string",
                        "description": "Business postcode"
                    },
                    "business_address_country": {
                        "type": "string",
                        "description": "Business country"
                    },
                    "business_phone": {
                        "type": "string",
                        "description": "Business phone number"
                    },
                    "auth_rep_title": {
                        "type": "string",
                        "description": "Authorised Representative title"
                    },
                    "auth_rep_first_name": {
                        "type": "string",
                        "description": "Authorised Representative first name"
                    },
                    "auth_rep_last_name": {
                        "type": "string",
                        "description": "Authorised Representative last name"
                    },
                    "auth_rep_email": {
                        "type": "string",
                        "description": "Authorised Representative email address"
                    },
                    "auth_rep_mobile": {
                        "type": "string",
                        "description": "Authorised Representative mobile number"
                    },
                    "already_registered_acma": {
                        "type": "integer",
                        "enum": [
                            0,
                            1
                        ],
                        "description": "Whether the sender ID is already registered with ACMA"
                    },
                    "sender_id_relationship": {
                        "type": "string",
                        "enum": [
                            "BUSINESS_NAME",
                            "COMPANY_NAME",
                            "TRADEMARK",
                            "DOMAIN",
                            "OTHER"
                        ],
                        "description": "The relationship between the sender ID and the registering entity"
                    },
                    "sender_id_relationship_value": {
                        "type": "string",
                        "description": "Description of relationship when sender_id_relationship=OTHER"
                    },
                    "authority": {
                        "type": "boolean",
                        "description": "Confirmed authorised to submit this registration"
                    },
                    "confirm_contact_permission": {
                        "type": "boolean",
                        "description": "Confirmed permission to provide the authorised representative's contact details"
                    },
                    "comments": {
                        "type": "string",
                        "description": "Additional comments"
                    },
                    "customer_has_abn": {
                        "type": "integer",
                        "enum": [
                            0,
                            1
                        ],
                        "description": "Whether the customer entity has an ABN or ACN"
                    },
                    "customer_company_number": {
                        "type": "string",
                        "description": "Customer ABN/ACN number"
                    },
                    "customer_company_name": {
                        "type": "string",
                        "description": "Customer company/entity name"
                    },
                    "customer_website": {
                        "type": "string",
                        "description": "Customer website or social media profile URL"
                    },
                    "customer_address_unit": {
                        "type": "string",
                        "description": "Customer unit/apartment number"
                    },
                    "customer_address_street_number": {
                        "type": "string",
                        "description": "Customer street number"
                    },
                    "customer_address_street": {
                        "type": "string",
                        "description": "Customer street name"
                    },
                    "customer_address_city": {
                        "type": "string",
                        "description": "Customer suburb"
                    },
                    "customer_address_state": {
                        "type": "string",
                        "enum": [
                            "ACT",
                            "NSW",
                            "NT",
                            "QLD",
                            "SA",
                            "TAS",
                            "VIC",
                            "WA"
                        ],
                        "description": "Customer state"
                    },
                    "customer_address_postcode": {
                        "type": "string",
                        "description": "Customer postcode"
                    },
                    "customer_address_country": {
                        "type": "string",
                        "description": "Customer country"
                    },
                    "customer_business_phone": {
                        "type": "string",
                        "description": "Customer business phone number"
                    },
                    "customer_auth_rep_title": {
                        "type": "string",
                        "description": "Customer authorised representative title"
                    },
                    "customer_auth_rep_first_name": {
                        "type": "string",
                        "description": "Customer authorised representative first name"
                    },
                    "customer_auth_rep_last_name": {
                        "type": "string",
                        "description": "Customer authorised representative last name"
                    },
                    "customer_auth_rep_email": {
                        "type": "string",
                        "description": "Customer authorised representative email address"
                    },
                    "customer_auth_rep_mobile": {
                        "type": "string",
                        "description": "Customer authorised representative mobile number"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When the registration was created (ISO8601)"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When the registration was last updated (ISO8601)"
                    },
                    "full_name": {
                        "type": "string",
                        "description": "Legacy field — full name of registrant (kept for backwards compatibility)"
                    },
                    "connection": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "description": "Legacy field — connection types (kept for backwards compatibility)"
                    },
                    "primary_uses": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "description": "Legacy field — primary uses for this sender ID (kept for backwards compatibility)"
                    },
                    "sample_messages": {
                        "type": "string",
                        "description": "Legacy field — sample messages (kept for backwards compatibility)"
                    }
                }
            },
            "SenderIdRecord": {
                "type": "object",
                "description": "Full ACMA registration record for a sender ID, as returned by `GET /sender_ids` (without `format=dropdown`) and `GET /sender_ids/{id}`.",
                "properties": {
                    "sender_id": {
                        "type": "integer",
                        "description": "Primary key of the senderids row."
                    },
                    "sender_value": {
                        "type": "string",
                        "description": "The sender ID string value."
                    },
                    "status": {
                        "type": "integer",
                        "enum": [
                            0,
                            1,
                            2,
                            10,
                            99
                        ],
                        "description": "0 = Received, 1 = Forwarded, 2 = Queried, 10 = Approved, 99 = Rejected. Always an integer (0 when unset)."
                    },
                    "owner": {
                        "type": "string",
                        "enum": [
                            "self",
                            "parent"
                        ],
                        "description": "`self` = registered by this account; `parent` = inherited from the parent account."
                    },
                    "is_editable": {
                        "type": "boolean",
                        "description": "Whether the authenticated user can edit or delete this sender ID registration. Parent-owned sender IDs are read-only for subaccounts."
                    },
                    "created_date": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_date": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "whofor": {
                        "type": "string",
                        "enum": [
                            "YOURS",
                            "OTHER"
                        ]
                    },
                    "company_number": {
                        "type": "string",
                        "nullable": true
                    },
                    "company_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "authority": {
                        "type": "integer",
                        "enum": [
                            0,
                            1
                        ]
                    },
                    "has_abn": {
                        "type": "integer",
                        "enum": [
                            0,
                            1
                        ]
                    },
                    "website": {
                        "type": "string",
                        "nullable": true
                    },
                    "business_address_unit": {
                        "type": "string",
                        "nullable": true
                    },
                    "business_address_street_number": {
                        "type": "string",
                        "nullable": true
                    },
                    "business_address_street": {
                        "type": "string",
                        "nullable": true
                    },
                    "business_address_city": {
                        "type": "string",
                        "nullable": true
                    },
                    "business_address_state": {
                        "type": "string",
                        "nullable": true
                    },
                    "business_address_postcode": {
                        "type": "string",
                        "nullable": true
                    },
                    "business_address_country": {
                        "type": "string",
                        "nullable": true
                    },
                    "business_phone": {
                        "type": "string",
                        "nullable": true
                    },
                    "auth_rep_title": {
                        "type": "string",
                        "nullable": true
                    },
                    "auth_rep_first_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "auth_rep_last_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "auth_rep_email": {
                        "type": "string",
                        "nullable": true
                    },
                    "auth_rep_mobile": {
                        "type": "string",
                        "nullable": true
                    },
                    "already_registered_acma": {
                        "type": "integer",
                        "enum": [
                            0,
                            1
                        ]
                    },
                    "sender_id_relationship": {
                        "type": "string",
                        "nullable": true
                    },
                    "sender_id_relationship_value": {
                        "type": "string",
                        "nullable": true
                    },
                    "comments": {
                        "type": "string",
                        "nullable": true
                    },
                    "confirm_contact_permission": {
                        "type": "integer",
                        "enum": [
                            0,
                            1
                        ]
                    },
                    "full_name": {
                        "type": "string",
                        "nullable": true,
                        "description": "Legacy field."
                    },
                    "connection": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "description": "Legacy field."
                    },
                    "primary_uses": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "description": "Legacy field."
                    },
                    "sample_messages": {
                        "type": "string",
                        "nullable": true,
                        "description": "Legacy field."
                    }
                }
            },
            "SenderIdDropdownItem": {
                "type": "object",
                "description": "Lightweight sender ID shape returned when `GET /sender_ids?format=dropdown` is called. Used by sender ID pickers. In addition to registered sender IDs, the dropdown list includes the account's assigned incoming numbers (own, plus the parent's when sender ID sharing is enabled). Incoming numbers appear in the phone shape (`is_phone: true`, `status: null`, `status_text: \"Incoming Number\"`, `allow_sending: true`) and are de-duplicated against any matching registered sender ID.",
                "properties": {
                    "senderid": {
                        "type": "string",
                        "description": "The sender ID string value, or an assigned incoming number."
                    },
                    "status": {
                        "type": "integer",
                        "nullable": true,
                        "enum": [
                            null,
                            0,
                            1,
                            2,
                            10,
                            99
                        ],
                        "description": "Registration status code. `null` for phone numbers and incoming numbers (no registration required)."
                    },
                    "owner": {
                        "type": "string",
                        "enum": [
                            "self",
                            "parent"
                        ],
                        "description": "`self` = owned by this account; `parent` = cascaded from the parent account."
                    },
                    "is_parent_owned": {
                        "type": "boolean",
                        "description": "Convenience boolean: `true` when `owner === 'parent'`."
                    },
                    "status_text": {
                        "type": "string",
                        "description": "Human-readable status label. `Incoming Number` for the account's assigned incoming numbers."
                    },
                    "icon": {
                        "type": "string",
                        "description": "Emoji icon for the status."
                    },
                    "color": {
                        "type": "string",
                        "description": "CSS hex colour for the status."
                    },
                    "allow_sending": {
                        "type": "boolean",
                        "description": "Whether this sender ID may currently be used for sending."
                    },
                    "is_phone": {
                        "type": "boolean",
                        "description": "Present and `true` when the value is a valid E.164 mobile phone number, including assigned incoming numbers. Omitted for alphanumeric sender IDs."
                    }
                }
            },
            "CardsResponse": {
                "type": "object",
                "description": "Unified response format for cards endpoints",
                "properties": {
                    "success": {
                        "type": "boolean",
                        "example": true
                    },
                    "message": {
                        "type": "string",
                        "description": "Human-readable status message",
                        "example": "Success"
                    },
                    "data": {
                        "type": "object",
                        "properties": {
                            "has_card": {
                                "type": "boolean",
                                "description": "Whether the user has a stored card",
                                "example": true
                            },
                            "ccapproval": {
                                "type": "integer",
                                "description": "User's credit card approval status from users.ccapproval (0=not approved, 1+=approved)",
                                "example": 3
                            },
                            "cards": {
                                "type": "array",
                                "description": "Array of stored cards (currently max 1 per user)",
                                "items": {
                                    "$ref": "#/components/schemas/Card"
                                }
                            }
                        }
                    },
                    "timestamp": {
                        "type": "string",
                        "format": "date-time",
                        "description": "Response timestamp in ISO8601 format",
                        "example": "2025-12-29T20:46:48+11:00"
                    }
                }
            }
        }
    }
}