{
  "openapi": "3.0.3",
  "info": {
    "title": "WebSMS API",
    "description": "SMS API for sending and receiving text messages. Integrate with Salesforce, HubSpot, Zapier, Shopify, Zoho CRM, and more.",
    "version": "1.0.0",
"contact": {
      "name": "WebSMS Support",
      "email": "support@websms.co.nz"
    }
  },
  "servers": [
    {
      "url": "https://api.websms.co.nz/api",
      "description": "Production (preferred)"
    },
    {
      "url": "https://websms.co.nz/api",
      "description": "Production (legacy host, also supported)"
    }
  ],
  "tags": [
    {
      "name": "Authentication",
      "description": "OAuth2-style API key authentication"
    },
    {
      "name": "SMS",
      "description": "Send SMS messages"
    },
    {
      "name": "Number Validation",
      "description": "Phone number validation and IPMS carrier lookup"
    },
    {
      "name": "Connexus",
      "description": "Connexus/Bulletin Connect compatible API - drop-in replacement for Bulletin Connect"
    },
    {
      "name": "Salesforce",
      "description": "Salesforce CRM integration"
    },
    {
      "name": "HubSpot",
      "description": "HubSpot CRM integration"
    },
    {
      "name": "Zapier",
      "description": "Zapier workflow integration"
    },
    {
      "name": "Shopify",
      "description": "Shopify e-commerce integration"
    },
    {
      "name": "Zoho",
      "description": "Zoho CRM integration"
    },
    {
      "name": "Outlook",
      "description": "Microsoft Outlook add-in (taskpane). Adds a 'New SMS' button to the Outlook ribbon."
    }
  ],
  "paths": {
    "/connexus/auth/token": {
      "post": {
        "tags": ["Authentication", "Connexus"],
        "summary": "Get Access Token",
        "description": "Exchange API key credentials (client_id + client_secret) for a Bearer access token. Tokens are valid for 24 hours.",
        "operationId": "getAccessToken",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token issued successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing client_id or client_secret",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid client credentials",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/send.php": {
      "get": {
        "tags": ["SMS"],
        "summary": "Send SMS (Legacy GET)",
        "description": "Send an SMS message using query parameters. This is the legacy API endpoint.",
        "operationId": "sendSmsLegacy",
        "parameters": [
          {
            "name": "username",
            "in": "query",
            "required": true,
            "description": "Your WebSMS username",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "password",
            "in": "query",
            "required": true,
            "description": "Your WebSMS password or API key",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cellnum",
            "in": "query",
            "required": true,
            "description": "Recipient phone number (e.g., 6421234567)",
            "schema": {
              "type": "string",
              "example": "6421234567"
            }
          },
          {
            "name": "message",
            "in": "query",
            "required": true,
            "description": "SMS message content",
            "schema": {
              "type": "string",
              "example": "Hello from WebSMS!"
            }
          },
          {
            "name": "sender",
            "in": "query",
            "required": false,
            "description": "Sender ID (shortcode or alphanumeric)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "SMS sent successfully",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "example": "SUCCESS:12345"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request parameters"
          },
          "401": {
            "description": "Authentication failed"
          }
        }
      }
    },
    "/connexus/number/lookup": {
      "post": {
        "tags": ["Number Validation", "Connexus"],
        "summary": "Phone Number Validation / IPMS Lookup",
        "description": "Validate a New Zealand mobile number and retrieve carrier information from the IPMS (Industry Portability Management System). Returns current carrier, portability status, and network details. Cost: $0.005 per lookup + GST.",
        "operationId": "connexusNumberLookup",
        "parameters": [
          {
            "name": "userId",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account email (not needed if using Bearer token)",
            "schema": { "type": "string", "example": "user@domain.co.nz" }
          },
          {
            "name": "password",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account password (not needed if using Bearer token)",
            "schema": { "type": "string" }
          },
          {
            "name": "number",
            "in": "query",
            "required": true,
            "description": "NZ mobile number to validate (local 02x or international 642x format)",
            "schema": { "type": "string", "example": "0211234567" }
          }
        ],
        "responses": {
          "200": {
            "description": "Number lookup successful",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NumberLookupResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid number format",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "tooShort": {
                    "summary": "Number too short",
                    "value": {
                      "success": false,
                      "error": "Invalid number",
                      "message": "Number too short. NZ mobile numbers must be 9-11 digits (e.g., 021234567)."
                    }
                  },
                  "tooLong": {
                    "summary": "Number too long",
                    "value": {
                      "success": false,
                      "error": "Invalid number",
                      "message": "Number too long. NZ mobile numbers must be 9-11 digits (e.g., 021234567)."
                    }
                  },
                  "invalidPrefix": {
                    "summary": "Invalid prefix",
                    "value": {
                      "success": false,
                      "error": "Invalid number",
                      "message": "Invalid prefix. NZ mobile numbers must start with 02X (e.g., 021, 022, 027)."
                    }
                  },
                  "invalidFormat": {
                    "summary": "Invalid format",
                    "value": {
                      "success": false,
                      "error": "Invalid number",
                      "message": "Invalid format. NZ mobile numbers must start with 02X (local) or 642X (international)."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient funds",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/connexus/sms/out": {
      "post": {
        "tags": ["Connexus"],
        "summary": "Send SMS",
        "description": "Send an SMS message to one or multiple recipients. For single recipient, use form-urlencoded with `to` as string. For multiple recipients, use JSON body with `to` as array. Supports Bearer token auth (recommended) or userId/password. For NZ numbers, response includes carrier/porting info.",
        "operationId": "connexusSendSms",
        "security": [
          { "bearerAuth": [] },
          {}
        ],
        "parameters": [
          {
            "name": "userId",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account email (not needed if using Bearer token)",
            "schema": { "type": "string", "example": "user@domain.co.nz" }
          },
          {
            "name": "password",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account password (not needed if using Bearer token)",
            "schema": { "type": "string" }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Recipient phone number (international format). For single recipient via form-urlencoded. For multiple recipients, use JSON body instead.",
            "schema": { "type": "string", "example": "6421234567" }
          },
          {
            "name": "body",
            "in": "query",
            "required": true,
            "description": "SMS message content",
            "schema": { "type": "string", "example": "Hello from WebSMS!" }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Sender ID (shortcode)",
            "schema": { "type": "string", "example": "2190" }
          },
          {
            "name": "messageClass",
            "in": "query",
            "required": true,
            "description": "Traffic classification for shortcode routing. Use `transactional` for OTP/2FA, confirmations, alerts, notifications and delivery updates; use `marketing` for promotional campaigns, offers and newsletters.",
            "schema": { "type": "string", "enum": ["transactional", "marketing"], "example": "transactional" }
          },
          {
            "name": "messageId",
            "in": "query",
            "required": false,
            "description": "Custom message identifier (max 36 chars). Echoed back as customerMessageId in delivery-status webhooks and /connexus/sms/status/query responses, as replyToCustomerMessageId in incoming-reply webhooks, and usable as the messageId lookup parameter on /connexus/sms/status/query. Not returned in the send response itself — that returns our message_id.",
            "schema": { "type": "string" }
          },
          {
            "name": "rateCode",
            "in": "query",
            "required": false,
            "description": "Message source identifier for reporting",
            "schema": { "type": "string" }
          },
          {
            "name": "fragmentationLimit",
            "in": "query",
            "required": false,
            "description": "Maximum SMS segments (0-3, default 3)",
            "schema": { "type": "integer", "example": 3 }
          },
          {
            "name": "schedule",
            "in": "query",
            "required": false,
            "description": "Unix timestamp for scheduled delivery",
            "schema": { "type": "integer" }
          },
          {
            "name": "sandbox",
            "in": "query",
            "required": false,
            "description": "Set to true to test without sending: no message is submitted and nothing is charged. The response echoes your message with its encoding (GSM-7/UCS-2), segment count and the price that would have been charged (sandbox_would_charge).",
            "schema": { "type": "boolean", "example": true }
          }
        ],
        "requestBody": {
          "description": "For sending to multiple recipients, use JSON body with `to` as an array",
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["to", "body", "messageClass"],
                "properties": {
                  "to": {
                    "type": "array",
                    "items": { "type": "string" },
                    "description": "Array of recipient phone numbers",
                    "example": ["6421111111", "6422222222"]
                  },
                  "body": {
                    "type": "string",
                    "description": "SMS message content",
                    "example": "Hello from WebSMS!"
                  },
                  "messageClass": {
                    "type": "string",
                    "enum": ["transactional", "marketing"],
                    "description": "Traffic classification for shortcode routing. Use `transactional` for OTP/2FA, confirmations, alerts, notifications and delivery updates; use `marketing` for promotional campaigns, offers and newsletters.",
                    "example": "transactional"
                  },
                  "from": {
                    "type": "string",
                    "description": "Sender ID (shortcode)",
                    "example": "2190"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SMS accepted for delivery",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnexusSendResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing required parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Insufficient funds or unauthorized shortcode",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/connexus/sms/in": {
      "post": {
        "tags": ["Connexus"],
        "summary": "Register Incoming SMS Webhook",
        "description": "Register a webhook URL to receive incoming SMS messages (MO - Mobile Originated).",
        "operationId": "connexusRegisterMoWebhook",
        "parameters": [
          {
            "name": "userId",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account email (not needed if using Bearer token)",
            "schema": { "type": "string", "example": "user@domain.co.nz" }
          },
          {
            "name": "password",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account password (not needed if using Bearer token)",
            "schema": { "type": "string" }
          },
          {
            "name": "url",
            "in": "query",
            "required": true,
            "description": "Webhook URL to receive incoming SMS",
            "schema": { "type": "string", "example": "https://yoursite.com/incoming" }
          }
        ],
        "responses": {
          "204": {
            "description": "Webhook registered successfully"
          },
          "400": {
            "description": "Missing or invalid URL"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/connexus/sms/status": {
      "post": {
        "tags": ["Connexus"],
        "summary": "Register Delivery Status Webhook",
        "description": "Register a webhook URL to receive delivery status updates (DLR - Delivery Reports).",
        "operationId": "connexusRegisterDlrWebhook",
        "parameters": [
          {
            "name": "userId",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account email (not needed if using Bearer token)",
            "schema": { "type": "string", "example": "user@domain.co.nz" }
          },
          {
            "name": "password",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account password (not needed if using Bearer token)",
            "schema": { "type": "string" }
          },
          {
            "name": "url",
            "in": "query",
            "required": true,
            "description": "Webhook URL to receive delivery status updates",
            "schema": { "type": "string", "example": "https://yoursite.com/status" }
          }
        ],
        "responses": {
          "204": {
            "description": "Webhook registered successfully"
          },
          "400": {
            "description": "Missing or invalid URL"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/connexus/sms/status/query": {
      "post": {
        "tags": ["Connexus"],
        "summary": "Query Delivery Status",
        "description": "Look up delivery status of sent messages. Three modes: (1) by message_id — up to 100 comma-separated IDs returned by /connexus/sms/out, any message age; (2) by messageId — your own custom identifier supplied when sending, any message age; (3) list mode — browse the current calendar month with optional filters and pagination (max 100 per page). Supports Bearer token auth or userId/password.",
        "operationId": "connexusQueryStatus",
        "security": [{ "bearerAuth": [] }, {}],
        "parameters": [
          {
            "name": "userId",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account email (not needed if using Bearer token)",
            "schema": { "type": "string", "example": "user@domain.co.nz" }
          },
          {
            "name": "password",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account password (not needed if using Bearer token)",
            "schema": { "type": "string" }
          },
          {
            "name": "message_id",
            "in": "query",
            "required": false,
            "description": "Comma-separated list of message IDs returned by /connexus/sms/out (max 100). No date restriction — works for any message age.",
            "schema": { "type": "string", "example": "1188236,1188240" }
          },
          {
            "name": "messageId",
            "in": "query",
            "required": false,
            "description": "Your own custom message identifier supplied when sending (max 100 matches returned). No date restriction.",
            "schema": { "type": "string", "example": "PRAC-042-7731" }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "List mode: filter by recipient number (exact match)",
            "schema": { "type": "string", "example": "6421234567" }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "List mode: filter by delivery status. PENDING also matches messages with no delivery report yet.",
            "schema": {
              "type": "string",
              "enum": ["DELIVRD", "UNDELIV", "ACCEPTD", "QUEUED", "FAILED", "PENDING", "BLOCKED", "DELETED", "UNKNOWN", "NACKED", "ENROUTE"],
              "example": "UNDELIV"
            }
          },
          {
            "name": "start_date",
            "in": "query",
            "required": false,
            "description": "List mode: start of date range (Y-m-d or Y-m-d H:i:s). Must fall within the current calendar month.",
            "schema": { "type": "string", "example": "2026-08-01 09:00:00" }
          },
          {
            "name": "end_date",
            "in": "query",
            "required": false,
            "description": "List mode: end of date range (Y-m-d or Y-m-d H:i:s). Must fall within the current calendar month.",
            "schema": { "type": "string", "example": "2026-08-09" }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "List mode: results per page (default: 50, max: 100)",
            "schema": { "type": "integer", "example": 50 }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "List mode: page number (default: 1)",
            "schema": { "type": "integer", "example": 1 }
          }
        ],
        "responses": {
          "200": {
            "description": "Statuses retrieved successfully",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ConnexusStatusQueryResponse" }
              }
            }
          },
          "400": {
            "description": "Invalid parameters (bad IDs, invalid status, or date range outside the current calendar month)"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/connexus/sms/otp": {
      "post": {
        "tags": ["Connexus"],
        "summary": "Send OTP/2FA Code",
        "description": "Send a one-time verification code for 2FA authentication. Code is auto-generated if not provided.",
        "operationId": "connexusSendOtp",
        "parameters": [
          {
            "name": "userId",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account email (not needed if using Bearer token)",
            "schema": { "type": "string", "example": "user@domain.co.nz" }
          },
          {
            "name": "password",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account password (not needed if using Bearer token)",
            "schema": { "type": "string" }
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Recipient phone number",
            "schema": { "type": "string", "example": "6421234567" }
          },
          {
            "name": "msgCompany",
            "in": "query",
            "required": true,
            "description": "Company/app name shown in message",
            "schema": { "type": "string", "example": "MyApp" }
          },
          {
            "name": "msgCode",
            "in": "query",
            "required": false,
            "description": "Custom 4-8 digit code (auto-generated if not provided)",
            "schema": { "type": "string", "example": "426817" }
          },
          {
            "name": "msgComment",
            "in": "query",
            "required": false,
            "description": "Additional text appended to message",
            "schema": { "type": "string", "example": "Valid for 5 minutes." }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Sender ID (default: 2190)",
            "schema": { "type": "string", "example": "2190" }
          }
        ],
        "responses": {
          "200": {
            "description": "OTP sent successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnexusOtpResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing required parameters"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "403": {
            "description": "Insufficient funds"
          }
        }
      }
    },
    "/connexus/sms/appointment": {
      "post": {
        "tags": ["Connexus"],
        "summary": "Send Appointment Reminder",
        "description": "Send a templated appointment reminder. The message is built from the supplied fields (greeting, company, date/time, confirm prompt, callback number, address) and charged at the template rate of $0.08 per segment for NZ/AU destinations (or your account rate if lower; international destinations use standard international rates). Supports Bearer token auth or userId/password.",
        "operationId": "connexusSendAppointment",
        "security": [{ "bearerAuth": [] }, {}],
        "parameters": [
          {
            "name": "userId",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account email (not needed if using Bearer token)",
            "schema": { "type": "string", "example": "user@domain.co.nz" }
          },
          {
            "name": "password",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account password (not needed if using Bearer token)",
            "schema": { "type": "string" }
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Recipient phone number",
            "schema": { "type": "string", "example": "6421234567" }
          },
          {
            "name": "msgCompany",
            "in": "query",
            "required": true,
            "description": "Business name shown in the reminder",
            "schema": { "type": "string", "example": "Lakeview Eyecare" }
          },
          {
            "name": "name",
            "in": "query",
            "required": false,
            "description": "Patient/customer first name for the greeting",
            "schema": { "type": "string", "example": "Sam" }
          },
          {
            "name": "date",
            "in": "query",
            "required": false,
            "description": "Appointment date (free text, shown as supplied)",
            "schema": { "type": "string", "example": "Tuesday 12 Aug" }
          },
          {
            "name": "time",
            "in": "query",
            "required": false,
            "description": "Appointment time (free text, shown as supplied)",
            "schema": { "type": "string", "example": "2:30pm" }
          },
          {
            "name": "replyY",
            "in": "query",
            "required": false,
            "description": "Set to true to append a 'Reply Y to confirm' prompt",
            "schema": { "type": "boolean", "example": true }
          },
          {
            "name": "callUs",
            "in": "query",
            "required": false,
            "description": "Phone number to call to re-book (appended to the confirm prompt)",
            "schema": { "type": "string", "example": "03 123 4567" }
          },
          {
            "name": "address",
            "in": "query",
            "required": false,
            "description": "Practice/business address appended to the message",
            "schema": { "type": "string" }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Sender shortcode (must be authorised for your account; defaults to the shared template shortcode)",
            "schema": { "type": "string", "example": "552" }
          },
          {
            "name": "sandbox",
            "in": "query",
            "required": false,
            "description": "Set to true to test without sending or charging - the response echoes the built message and price",
            "schema": { "type": "boolean" }
          }
        ],
        "responses": {
          "200": {
            "description": "Reminder sent successfully",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ConnexusSendResponse" }
              }
            }
          },
          "400": {
            "description": "Missing to or msgCompany"
          },
          "401": {
            "description": "Invalid credentials"
          },
          "403": {
            "description": "Insufficient funds or unauthorised sender"
          }
        }
      }
    },
    "/connexus/sms/balance": {
      "post": {
        "tags": ["Connexus"],
        "summary": "Check Account Balance",
        "description": "Query your account balance before sending messages.",
        "operationId": "connexusCheckBalance",
        "parameters": [
          {
            "name": "userId",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account email (not needed if using Bearer token)",
            "schema": { "type": "string", "example": "user@domain.co.nz" }
          },
          {
            "name": "password",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account password (not needed if using Bearer token)",
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Balance retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnexusBalanceResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/connexus/mo/query": {
      "post": {
        "tags": ["Connexus"],
        "summary": "Query Incoming Messages",
        "description": "Query received mobile-originated messages with filters and pagination.",
        "operationId": "connexusQueryMo",
        "parameters": [
          {
            "name": "userId",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account email (not needed if using Bearer token)",
            "schema": { "type": "string", "example": "user@domain.co.nz" }
          },
          {
            "name": "password",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account password (not needed if using Bearer token)",
            "schema": { "type": "string" }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Filter by sender number",
            "schema": { "type": "string", "example": "6421234567" }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Filter by recipient (shortcode)",
            "schema": { "type": "string", "example": "551" }
          },
          {
            "name": "callback_status",
            "in": "query",
            "required": false,
            "description": "Filter by the HTTP status code your webhook returned (e.g. 200, 500). Useful for finding messages whose webhook delivery failed.",
            "schema": { "type": "string", "example": "200" }
          },
          {
            "name": "start_date",
            "in": "query",
            "required": false,
            "description": "Start of date range (Y-m-d or Y-m-d H:i:s)",
            "schema": { "type": "string", "example": "2025-01-01" }
          },
          {
            "name": "end_date",
            "in": "query",
            "required": false,
            "description": "End of date range (Y-m-d or Y-m-d H:i:s)",
            "schema": { "type": "string", "example": "2025-01-31" }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Results per page (default: 100, max: 200)",
            "schema": { "type": "integer", "example": 100 }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Page number (default: 1)",
            "schema": { "type": "integer", "example": 1 }
          }
        ],
        "responses": {
          "200": {
            "description": "Messages retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnexusMoQueryResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/connexus/unsubscribes/query": {
      "post": {
        "tags": ["Connexus"],
        "summary": "Query Blocked (Unsubscribed) Numbers",
        "description": "Fetch numbers that have opted out (STOP/END) of receiving messages from your account — the same list as Members Area > Blocked Numbers. Designed for delta syncing: pass `since` to fetch only entries blocked or resubscribed after that time, and use include=all to also receive resubscribed entries (active=false) so you can unblock them on your side. Supports Bearer token auth or userId/password.",
        "operationId": "connexusQueryUnsubscribes",
        "security": [{ "bearerAuth": [] }, {}],
        "parameters": [
          {
            "name": "userId",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account email (not needed if using Bearer token)",
            "schema": { "type": "string", "example": "user@domain.co.nz" }
          },
          {
            "name": "password",
            "in": "query",
            "required": false,
            "description": "Your WebSMS account password (not needed if using Bearer token)",
            "schema": { "type": "string" }
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Only entries blocked or resubscribed at/after this time (Y-m-d or Y-m-d H:i:s). Omit for the full current list.",
            "schema": { "type": "string", "example": "2026-08-01" }
          },
          {
            "name": "include",
            "in": "query",
            "required": false,
            "description": "'active' (default) = currently blocked numbers only; 'all' = also include resubscribed entries with active=false",
            "schema": { "type": "string", "enum": ["active", "all"], "example": "active" }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Results per page (default: 100, max: 200)",
            "schema": { "type": "integer", "example": 100 }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Page number (default: 1)",
            "schema": { "type": "integer", "example": 1 }
          }
        ],
        "responses": {
          "200": {
            "description": "Blocked numbers retrieved successfully",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ConnexusUnsubscribesResponse" }
              }
            }
          },
          "400": {
            "description": "Invalid since date or include value"
          },
          "401": {
            "description": "Invalid credentials"
          }
        }
      }
    },
    "/salesforce/workflow.php": {
      "post": {
        "tags": ["Salesforce"],
        "summary": "Send SMS from Salesforce",
        "description": "Endpoint for Salesforce Flow HTTP Callout or Apex HttpRequest to send SMS messages. Use this URL in your Salesforce Flow's HTTP Callout action.",
        "operationId": "sendSmsFromSalesforce",
        "parameters": [
          {
            "name": "cust_id",
            "in": "query",
            "required": true,
            "description": "Your WebSMS customer ID",
            "schema": {
              "type": "integer",
              "example": 123
            }
          },
          {
            "name": "shortcode_id",
            "in": "query",
            "required": true,
            "description": "Your shortcode ID",
            "schema": {
              "type": "integer",
              "example": 456
            }
          },
          {
            "name": "key",
            "in": "query",
            "required": true,
            "description": "API key from WebSMS integrations page",
            "schema": {
              "type": "string",
              "example": "abc123def456..."
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendSmsRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Basic SMS",
                  "value": {
                    "to": "+6421234567",
                    "message": "Hello from Salesforce!"
                  }
                },
                "withMergeFields": {
                  "summary": "With Salesforce merge fields",
                  "value": {
                    "to": "{!Contact.Phone}",
                    "message": "Hi {!Contact.FirstName}, your appointment is confirmed for {!Event.StartDateTime}."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SMS sent successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendSmsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request - missing or invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed - invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient SMS balance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Integration disabled or not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/hubspot/workflow.php": {
      "post": {
        "tags": ["HubSpot"],
        "summary": "Send SMS from HubSpot Workflow",
        "description": "Endpoint for HubSpot Workflows to send SMS messages. Add this as a webhook action in your HubSpot workflow.",
        "operationId": "sendSmsFromHubspot",
        "parameters": [
          {
            "name": "cust_id",
            "in": "query",
            "required": true,
            "description": "Your WebSMS customer ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "shortcode_id",
            "in": "query",
            "required": true,
            "description": "Your shortcode ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "secret",
            "in": "query",
            "required": true,
            "description": "Webhook secret from WebSMS integrations page",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendSmsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SMS sent successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendSmsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request"
          },
          "401": {
            "description": "Authentication failed"
          }
        }
      }
    },
    "/zapier/webhook.php": {
      "post": {
        "tags": ["Zapier"],
        "summary": "Send SMS from Zapier",
        "description": "Endpoint for Zapier actions to send SMS messages. Use this URL in your Zap's webhook action.",
        "operationId": "sendSmsFromZapier",
        "parameters": [
          {
            "name": "cust_id",
            "in": "query",
            "required": true,
            "description": "Your WebSMS customer ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "shortcode_id",
            "in": "query",
            "required": true,
            "description": "Your shortcode ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "key",
            "in": "query",
            "required": true,
            "description": "API key from WebSMS integrations page",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendSmsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SMS sent successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendSmsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request"
          },
          "401": {
            "description": "Authentication failed"
          }
        }
      }
    },
    "/shopify/webhook.php": {
      "post": {
        "tags": ["Shopify"],
        "summary": "Shopify Order Webhook",
        "description": "Receives order events from Shopify and sends SMS notifications. Configure this URL in Shopify Admin > Settings > Notifications > Webhooks.",
        "operationId": "shopifyWebhook",
        "parameters": [
          {
            "name": "cust_id",
            "in": "query",
            "required": true,
            "description": "Your WebSMS customer ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "shortcode_id",
            "in": "query",
            "required": true,
            "description": "Your shortcode ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "key",
            "in": "query",
            "required": true,
            "description": "API key from WebSMS integrations page",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Shopify order payload (sent automatically by Shopify)",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Shopify order object - see Shopify documentation for full schema"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook processed successfully"
          },
          "401": {
            "description": "Authentication failed"
          }
        }
      }
    },
    "/zoho/send.php": {
      "post": {
        "tags": ["Zoho"],
        "summary": "Send SMS from Zoho CRM",
        "description": "Send SMS messages from Zoho CRM workflows, custom functions, or buttons. Supports two authentication modes: API key (for shared shortcodes) or webhook secret (for owned shortcodes).",
        "operationId": "sendSmsFromZoho",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ZohoSendRequest"
              },
              "examples": {
                "sharedShortcode": {
                  "summary": "Using API Key (Shared Shortcode)",
                  "description": "For customers using the shared 2190 shortcode",
                  "value": {
                    "api_key": "zoho_abc123...",
                    "to": "+6421234567",
                    "message": "Hello from Zoho CRM!"
                  }
                },
                "ownedShortcode": {
                  "summary": "Using Webhook Secret (Owned Shortcode)",
                  "description": "For customers with their own dedicated shortcode",
                  "value": {
                    "shortcode_id": 123,
                    "secret": "your_webhook_secret",
                    "to": "+6421234567",
                    "message": "Hello from Zoho CRM!"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SMS sent successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZohoSendResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request - missing or invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "missingFields": {
                    "value": {
                      "success": false,
                      "error": "Missing required fields: to, message"
                    }
                  },
                  "invalidPhone": {
                    "value": {
                      "success": false,
                      "error": "Invalid phone number"
                    }
                  },
                  "missingAuth": {
                    "value": {
                      "success": false,
                      "error": "Authentication required: provide either api_key OR (shortcode_id + secret)"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalidApiKey": {
                    "value": {
                      "success": false,
                      "error": "Invalid API key"
                    }
                  },
                  "integrationDisabled": {
                    "value": {
                      "success": false,
                      "error": "Zoho integration is disabled"
                    }
                  },
                  "invalidSecret": {
                    "value": {
                      "success": false,
                      "error": "Invalid webhook secret"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/outlook/send.php": {
      "post": {
        "tags": ["Outlook"],
        "summary": "Send SMS from the Outlook add-in",
        "description": "Called by the WebSMS Outlook add-in (taskpane) when the user clicks Send. Authenticate with the X-API-Key header containing the per-shortcode key from /members/integrations.php. Phone numbers default to NZ (+64) when no country code is supplied.",
        "operationId": "sendSmsFromOutlook",
        "parameters": [
          {
            "name": "X-API-Key",
            "in": "header",
            "required": true,
            "schema": { "type": "string" },
            "description": "WebSMS API key for the Outlook integration on a specific shortcode."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SendSmsRequest" },
              "examples": {
                "basic": {
                  "summary": "Send to one recipient",
                  "value": { "to": "+6421234567", "message": "Hello from Outlook" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SMS sent (or queued for review/nighttime delivery)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SendSmsResponse" }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
          },
          "402": {
            "description": "Insufficient prepaid balance",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
          },
          "500": {
            "description": "Internal server error",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "SendSmsRequest": {
        "type": "object",
        "required": ["to", "message"],
        "properties": {
          "to": {
            "type": "string",
            "description": "Recipient phone number. Can include country code (64) or start with 0 for NZ numbers.",
            "example": "+6421234567"
          },
          "message": {
            "type": "string",
            "description": "SMS message content. Max 1600 characters (10 segments).",
            "example": "Hello from WebSMS!",
            "maxLength": 1600
          },
          "phone": {
            "type": "string",
            "description": "Alternative field name for phone number (alias for 'to')",
            "example": "+6421234567"
          },
          "text": {
            "type": "string",
            "description": "Alternative field name for message (alias for 'message')",
            "example": "Hello from WebSMS!"
          }
        }
      },
      "SendSmsResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the SMS was sent successfully",
            "example": true
          },
          "messageId": {
            "type": "string",
            "description": "Unique message ID for tracking",
            "example": "12345"
          },
          "to": {
            "type": "string",
            "description": "Normalized phone number the message was sent to",
            "example": "6421234567"
          },
          "segments": {
            "type": "integer",
            "description": "Number of SMS segments used",
            "example": 1
          },
          "status": {
            "type": "string",
            "description": "Message status",
            "example": "sent"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": false
          },
          "error": {
            "type": "string",
            "description": "Error message describing what went wrong",
            "example": "Invalid API key"
          }
        }
      },
      "ConnexusAuthRequest": {
        "type": "object",
        "required": ["userId", "password"],
        "properties": {
          "userId": {
            "type": "string",
            "description": "Your WebSMS account email",
            "example": "user@domain.co.nz"
          },
          "password": {
            "type": "string",
            "description": "Your WebSMS account password",
            "example": "yourpassword"
          }
        }
      },
      "ConnexusSendRequest": {
        "type": "object",
        "required": ["userId", "password", "to", "body", "messageClass"],
        "properties": {
          "userId": {
            "type": "string",
            "description": "Your WebSMS account email",
            "example": "user@domain.co.nz"
          },
          "password": {
            "type": "string",
            "description": "Your WebSMS account password",
            "example": "yourpassword"
          },
          "to": {
            "type": "string",
            "description": "Recipient phone number (international format)",
            "example": "6421234567"
          },
          "body": {
            "type": "string",
            "description": "SMS message content",
            "example": "Hello from WebSMS!"
          },
          "messageClass": {
            "type": "string",
            "enum": ["transactional", "marketing"],
            "description": "Traffic classification for shortcode routing. Use `transactional` for OTP/2FA, confirmations, alerts, notifications and delivery updates; use `marketing` for promotional campaigns, offers and newsletters.",
            "example": "transactional"
          },
          "from": {
            "type": "string",
            "description": "Sender ID (shortcode)",
            "example": "2190"
          },
          "messageId": {
            "type": "string",
            "description": "Custom message identifier (max 36 chars). Echoed back as customerMessageId in delivery-status webhooks and /connexus/sms/status/query responses, as replyToCustomerMessageId in incoming-reply webhooks, and usable as the messageId lookup parameter on /connexus/sms/status/query. Not returned in the send response itself — that returns our message_id.",
            "example": "MSG123456"
          },
          "rateCode": {
            "type": "string",
            "description": "Message source identifier for reporting",
            "example": "CAMPAIGN1"
          },
          "fragmentationLimit": {
            "type": "integer",
            "description": "Maximum SMS segments (0-3, default 3)",
            "example": 3
          },
          "schedule": {
            "type": "integer",
            "description": "Unix timestamp for scheduled delivery",
            "example": 1735689600
          }
        }
      },
      "ConnexusSendResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the message was accepted",
            "example": true
          },
          "status": {
            "type": "string",
            "description": "Message status",
            "example": "accepted"
          },
          "message_id": {
            "type": "string",
            "description": "Unique message ID for this send. This is the correlation key across the API: delivery-status webhooks reference it as messageId, incoming reply webhooks reference it as replyTo, /connexus/mo/query returns it as relatedMessageId, and /connexus/sms/status/query accepts it as the message_id lookup parameter.",
            "example": "1188236"
          },
          "to": {
            "type": "string",
            "description": "Normalized recipient phone number",
            "example": "6421234567"
          },
          "from": {
            "type": "string",
            "description": "Sender ID used",
            "example": "2190"
          },
          "parts": {
            "type": "integer",
            "description": "Number of SMS segments",
            "example": 1
          },
          "route": {
            "type": "string",
            "description": "SMSC route used for delivery (NZ numbers only)",
            "example": "smsc_2degrees"
          },
          "porting": {
            "type": "object",
            "description": "Carrier/porting information (NZ numbers with IPMS data only)",
            "properties": {
              "ported": {
                "type": "boolean",
                "description": "Whether the number has been ported",
                "example": false
              },
              "carrier": {
                "type": "string",
                "description": "Current carrier name",
                "example": "2degrees"
              },
              "source": {
                "type": "string",
                "description": "Data source (redis or ipms)",
                "example": "redis"
              }
            }
          }
        }
      },
      "ConnexusBulkSendResponse": {
        "type": "object",
        "description": "Response when sending to multiple recipients",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether at least one message was sent successfully",
            "example": true
          },
          "messages": {
            "type": "array",
            "description": "Array of results for each recipient",
            "items": {
              "$ref": "#/components/schemas/ConnexusSendResponse"
            }
          },
          "summary": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer",
                "description": "Total number of recipients",
                "example": 2
              },
              "sent": {
                "type": "integer",
                "description": "Number of messages successfully sent",
                "example": 2
              },
              "failed": {
                "type": "integer",
                "description": "Number of messages that failed",
                "example": 0
              }
            }
          }
        }
      },
      "TokenRequest": {
        "type": "object",
        "required": ["client_id", "client_secret"],
        "properties": {
          "client_id": {
            "type": "string",
            "description": "API key public identifier (cid_xxx format)",
            "example": "cid_abc123..."
          },
          "client_secret": {
            "type": "string",
            "description": "API key secret (csk_xxx format)",
            "example": "csk_xyz789..."
          }
        }
      },
      "TokenResponse": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string",
            "description": "Bearer token for API authentication",
            "example": "wst_abc123..."
          },
          "token_type": {
            "type": "string",
            "description": "Token type (always 'Bearer')",
            "example": "Bearer"
          },
          "expires_in": {
            "type": "integer",
            "description": "Token validity in seconds (86400 = 24 hours)",
            "example": 86400
          }
        }
      },
      "ConnexusWebhookRequest": {
        "type": "object",
        "required": ["userId", "password", "url"],
        "properties": {
          "userId": {
            "type": "string",
            "description": "Your WebSMS account email",
            "example": "user@domain.co.nz"
          },
          "password": {
            "type": "string",
            "description": "Your WebSMS account password",
            "example": "yourpassword"
          },
          "url": {
            "type": "string",
            "description": "Webhook URL to receive callbacks",
            "example": "https://yoursite.com/webhook"
          }
        }
      },
      "ConnexusOtpRequest": {
        "type": "object",
        "required": ["userId", "password", "to", "msgCompany"],
        "properties": {
          "userId": {
            "type": "string",
            "description": "Your WebSMS account email",
            "example": "user@domain.co.nz"
          },
          "password": {
            "type": "string",
            "description": "Your WebSMS account password",
            "example": "yourpassword"
          },
          "to": {
            "type": "string",
            "description": "Recipient phone number",
            "example": "6421234567"
          },
          "msgCompany": {
            "type": "string",
            "description": "Company/app name shown in message",
            "example": "MyApp"
          },
          "msgCode": {
            "type": "string",
            "description": "Custom 4-8 digit code (auto-generated if not provided)",
            "example": "426817"
          },
          "msgComment": {
            "type": "string",
            "description": "Additional text appended to message",
            "example": "Valid for 5 minutes."
          },
          "from": {
            "type": "string",
            "description": "Sender ID (default: 2190)",
            "example": "2190"
          }
        }
      },
      "ConnexusOtpResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "example": "success"
          },
          "message_id": {
            "type": "string",
            "description": "Unique message ID",
            "example": "abc123def456"
          },
          "to": {
            "type": "string",
            "description": "Recipient phone number",
            "example": "6421234567"
          },
          "from": {
            "type": "string",
            "description": "Sender ID used",
            "example": "2190"
          },
          "code": {
            "type": "string",
            "description": "The OTP code that was sent (store this to verify later)",
            "example": "426817"
          },
          "parts": {
            "type": "integer",
            "description": "Number of SMS segments",
            "example": 1
          }
        }
      },
      "ConnexusBalanceResponse": {
        "type": "object",
        "properties": {
          "balance": {
            "type": "string",
            "description": "Current account balance",
            "example": "125.50"
          },
          "currency": {
            "type": "string",
            "description": "Currency code",
            "example": "NZD"
          }
        }
      },
      "NumberLookupResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the lookup was successful",
            "example": true
          },
          "number": {
            "type": "string",
            "description": "Normalized phone number (international format)",
            "example": "6421234567"
          },
          "carrier": {
            "type": "string",
            "description": "Current carrier name",
            "example": "Spark"
          },
          "ported": {
            "type": "boolean",
            "description": "Whether the number has been ported from its original network",
            "example": false
          },
          "original_network": {
            "type": "string",
            "description": "Original network based on number prefix",
            "example": "Spark"
          },
          "current_network": {
            "type": "string",
            "description": "Current network servicing the number",
            "example": "Spark"
          },
          "network_code": {
            "type": "string",
            "description": "Network operator code",
            "example": "TCNZ"
          }
        }
      },
      "ConnexusMoQueryRequest": {
        "type": "object",
        "required": ["userId", "password"],
        "properties": {
          "userId": {
            "type": "string",
            "description": "Your WebSMS account email",
            "example": "user@domain.co.nz"
          },
          "password": {
            "type": "string",
            "description": "Your WebSMS account password",
            "example": "yourpassword"
          },
          "from": {
            "type": "string",
            "description": "Filter by sender number",
            "example": "6421234567"
          },
          "to": {
            "type": "string",
            "description": "Filter by recipient (shortcode)",
            "example": "551"
          },
          "callback_status": {
            "type": "string",
            "description": "Filter by the HTTP status code your webhook returned (e.g. 200, 500). Useful for finding messages whose webhook delivery failed.",
            "example": "200"
          },
          "start_date": {
            "type": "string",
            "description": "Start of date range (Y-m-d or Y-m-d H:i:s)",
            "example": "2025-01-01"
          },
          "end_date": {
            "type": "string",
            "description": "End of date range (Y-m-d or Y-m-d H:i:s)",
            "example": "2025-01-31"
          },
          "limit": {
            "type": "integer",
            "description": "Results per page (default: 100, max: 200)",
            "example": 100
          },
          "page": {
            "type": "integer",
            "description": "Page number (default: 1)",
            "example": 1
          }
        }
      },
      "ConnexusMoQueryResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "example": "success"
          },
          "messages": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "messageId": {
                  "type": "string",
                  "description": "Unique ID of this incoming message",
                  "example": "1234"
                },
                "from": {
                  "type": "string",
                  "example": "6421234567"
                },
                "to": {
                  "type": "string",
                  "example": "551"
                },
                "body": {
                  "type": "string",
                  "example": "Reply message text"
                },
                "receivedTime": {
                  "type": "string",
                  "example": "2025-01-15 14:30:00"
                },
                "timestamp": {
                  "type": "integer",
                  "example": 1736948400
                },
                "relatedMessageId": {
                  "type": "string",
                  "description": "Present when this message is a reply to a message you sent: the message_id returned by /connexus/sms/out for that original message (also delivered as replyTo in the incoming-SMS webhook). Omitted for keyword/user-initiated messages with no prior outbound message.",
                  "example": "1188236"
                },
                "callbackUrl": {
                  "type": "string",
                  "description": "Webhook URL this message was delivered to (only present if a webhook call was made)",
                  "example": "https://yoursite.com/webhook"
                },
                "callbackStatus": {
                  "type": "string",
                  "description": "HTTP status code returned by your webhook endpoint (only present if a webhook call was made)",
                  "example": "200"
                },
                "callbackResponse": {
                  "type": "string",
                  "description": "Response body returned by your webhook endpoint, truncated to 500 characters (only present if a webhook call was made)",
                  "example": "OK"
                }
              }
            }
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "example": 1
              },
              "limit": {
                "type": "integer",
                "example": 100
              },
              "totalRecords": {
                "type": "integer",
                "example": 250
              },
              "totalPages": {
                "type": "integer",
                "example": 3
              },
              "hasNextPage": {
                "type": "boolean",
                "example": true
              },
              "hasPreviousPage": {
                "type": "boolean",
                "example": false
              }
            }
          }
        }
      },
      "ConnexusStatusQueryResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "example": "success"
          },
          "messages": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "message_id": {
                  "type": "string",
                  "description": "The message ID returned by /connexus/sms/out",
                  "example": "1188236"
                },
                "to": {
                  "type": "string",
                  "example": "6421234567"
                },
                "from": {
                  "type": "string",
                  "example": "2190"
                },
                "status": {
                  "type": "string",
                  "description": "Delivery status. PENDING means no delivery report has been received yet. Same status strings as the delivery-status webhook.",
                  "enum": ["DELIVRD", "UNDELIV", "ACCEPTD", "QUEUED", "FAILED", "PENDING", "BLOCKED", "DELETED", "UNKNOWN", "NACKED", "ENROUTE"],
                  "example": "DELIVRD"
                },
                "statusCode": {
                  "type": "integer",
                  "nullable": true,
                  "description": "Raw delivery report code (null if no report received yet)",
                  "example": 1
                },
                "sentTime": {
                  "type": "string",
                  "description": "When the message was submitted",
                  "example": "2026-08-09 10:15:22"
                },
                "statusTime": {
                  "type": "string",
                  "description": "When the delivery status was last updated (only present once a report has arrived)",
                  "example": "2026-08-09 10:15:31"
                },
                "customerMessageId": {
                  "type": "string",
                  "description": "Your own custom messageId supplied when sending (only present if you supplied one)",
                  "example": "PRAC-042-7731"
                },
                "blockedReason": {
                  "type": "string",
                  "description": "Reason the message was blocked before submission (only present when status is BLOCKED)",
                  "example": "unsubscribed"
                }
              }
            }
          },
          "notFound": {
            "type": "array",
            "description": "message_id lookups only: requested IDs that were not found on your account",
            "items": { "type": "string" },
            "example": []
          },
          "pagination": {
            "type": "object",
            "description": "List mode only",
            "properties": {
              "page": { "type": "integer", "example": 1 },
              "limit": { "type": "integer", "example": 50 },
              "totalRecords": { "type": "integer", "example": 250 },
              "totalPages": { "type": "integer", "example": 5 },
              "hasNextPage": { "type": "boolean", "example": true },
              "hasPreviousPage": { "type": "boolean", "example": false }
            }
          }
        }
      },
      "ConnexusUnsubscribesResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "example": "success"
          },
          "numbers": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "number": {
                  "type": "string",
                  "description": "The opted-out mobile number",
                  "example": "6421234567"
                },
                "keyword": {
                  "type": "string",
                  "description": "The keyword that triggered the opt-out",
                  "example": "STOP"
                },
                "blockedAt": {
                  "type": "string",
                  "description": "When the number opted out (refreshed if they STOP again)",
                  "example": "2026-08-05 14:22:10"
                },
                "active": {
                  "type": "boolean",
                  "description": "true = currently blocked; false = has since resubscribed (only returned with include=all)",
                  "example": true
                },
                "shortcode": {
                  "type": "string",
                  "description": "Shortcode the STOP was sent to (only present when known)",
                  "example": "2190"
                },
                "resubscribedAt": {
                  "type": "string",
                  "description": "When the number resubscribed (only present if they did)",
                  "example": "2026-08-07 09:01:44"
                }
              }
            }
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": { "type": "integer", "example": 1 },
              "limit": { "type": "integer", "example": 100 },
              "totalRecords": { "type": "integer", "example": 42 },
              "totalPages": { "type": "integer", "example": 1 },
              "hasNextPage": { "type": "boolean", "example": false },
              "hasPreviousPage": { "type": "boolean", "example": false }
            }
          }
        }
      },
      "ZohoSendRequest": {
        "type": "object",
        "required": ["to", "message"],
        "properties": {
          "api_key": {
            "type": "string",
            "description": "API key for shared shortcode authentication. Get this from WebSMS Integrations page.",
            "example": "zoho_abc123..."
          },
          "shortcode_id": {
            "type": "integer",
            "description": "Shortcode ID for owned shortcode authentication. Use with 'secret' parameter.",
            "example": 123
          },
          "secret": {
            "type": "string",
            "description": "Webhook secret for owned shortcode authentication. Use with 'shortcode_id' parameter.",
            "example": "your_webhook_secret"
          },
          "to": {
            "type": "string",
            "description": "Recipient phone number. Can include country code (64) or start with 0 for NZ numbers.",
            "example": "+6421234567"
          },
          "message": {
            "type": "string",
            "description": "SMS message content. Max 1600 characters (10 segments).",
            "example": "Hello from Zoho CRM!",
            "maxLength": 1600
          }
        }
      },
      "ZohoSendResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the SMS was sent successfully",
            "example": true
          },
          "message_id": {
            "type": "integer",
            "description": "Unique message ID for tracking",
            "example": 12345
          },
          "segments": {
            "type": "integer",
            "description": "Number of SMS segments used",
            "example": 1
          },
          "from": {
            "type": "string",
            "description": "Sender shortcode used",
            "example": "2190"
          }
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Bearer token from /connexus/auth/token endpoint. Valid for 24 hours."
      },
      "apiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "key",
        "description": "API key passed as query parameter"
      },
      "basicAuth": {
        "type": "http",
        "scheme": "basic",
        "description": "Username (email) and password authentication"
      }
    }
  }
}
