openapi: 3.1.0 info: title: 'IntelliSend Developers' description: 'Send transactional and marketing SMS, manage OTP verification, and track campaign delivery through IntelliSend.' version: 1.0.0 servers: - url: 'https://your-workspace.example' tags: - name: 'Developer SMS' description: '' - name: 'Developer OTP' description: '' components: securitySchemes: default: type: http scheme: bearer description: 'Create a scoped API key in Developer Tools. Never use a browser session cookie for this API.' security: - default: [] paths: /api/v1/messages: post: summary: 'Send SMS' operationId: sendSMS description: "Requires the `messages:send` ability. Send to 1–1,000 distinct E.164 recipients.\n\nOmitted routing uses the API key's routing, which defaults to IntelliSend. Explicit request routing overrides the key; workspace Quick SMS defaults do not apply.\n\nA `202` response records the request, not handset delivery. Inspect `data.queue.success`: when false, check the message status before retrying. Use the same Idempotency-Key for retries of the same send. See [routing](#routing) and [safe retries](#reference)." parameters: - in: header name: Idempotency-Key description: '' schema: type: string examples: - sms-20260912-001 responses: 202: description: '' content: application/json: schema: oneOf: - description: Queued type: object properties: message: type: string examples: - 'SMS queued.' data: type: object properties: message: type: object properties: id: type: integer description: 'Campaign ID to use for a status lookup.' examples: - 123 reference: type: string description: 'Your customer reference, or null.' examples: - order-1042 status: type: string description: 'Current campaign processing status; not a handset delivery receipt.' examples: - queued total_recipients: type: integer description: 'Number of recipients recorded on the campaign.' examples: - 1 queued_count: type: integer description: 'Messages currently queued.' examples: - 1 sent_count: type: integer description: 'Messages submitted to a provider, not confirmed handset deliveries.' examples: - 0 failed_count: type: integer description: 'Messages that failed to send.' examples: - 0 created_at: type: string description: 'ISO 8601 creation timestamp.' examples: - '2026-09-12T10:00:00+00:00' completed_at: type: string description: 'ISO 8601 completion timestamp, or null while incomplete.' examples: - null queue: type: object properties: success: type: boolean description: 'Whether the request was successfully queued. If false, check status before taking another action.' examples: - true campaign_id: type: integer examples: - 123 batch_id: type: string examples: - 97d7b8db-45cc-4498-92bf-a9739436c287 total_recipients: type: integer examples: - 1 requested_recipients: type: integer description: 'Requested recipient count; present when queued successfully.' examples: - 1 excluded_recipients: type: integer description: 'Recipients excluded from the queued send; present when queued successfully.' examples: - 0 message: type: string examples: - 'Campaign queued for sending' examples: - message: 'SMS queued.' data: message: id: 123 reference: order-1042 status: queued total_recipients: 1 queued_count: 1 sent_count: 0 failed_count: 0 created_at: '2026-09-12T10:00:00+00:00' completed_at: null queue: success: true campaign_id: 123 batch_id: 97d7b8db-45cc-4498-92bf-a9739436c287 total_recipients: 1 requested_recipients: 1 excluded_recipients: 0 message: 'Campaign queued for sending' - description: 'Saved; check status' type: object properties: message: type: string examples: - 'SMS request saved. Check the campaign status.' data: type: object properties: message: type: object properties: id: type: integer description: 'Campaign ID to use for a status lookup.' examples: - 123 reference: type: string description: 'Your customer reference, or null.' examples: - order-1042 status: type: string description: 'Current campaign processing status; not a handset delivery receipt.' examples: - paused total_recipients: type: integer description: 'Number of recipients recorded on the campaign.' examples: - 1 queued_count: type: integer description: 'Messages currently queued.' examples: - 1 sent_count: type: integer description: 'Messages submitted to a provider, not confirmed handset deliveries.' examples: - 0 failed_count: type: integer description: 'Messages that failed to send.' examples: - 0 created_at: type: string description: 'ISO 8601 creation timestamp.' examples: - '2026-09-12T10:00:00+00:00' completed_at: type: string description: 'ISO 8601 completion timestamp, or null while incomplete.' examples: - null queue: type: object properties: success: type: boolean description: 'Whether the request was successfully queued. If false, check status before taking another action.' examples: - false campaign_id: type: integer examples: - 123 message: type: string examples: - 'Queue dispatch could not be confirmed. Review this campaign before resuming.' examples: - message: 'SMS request saved. Check the campaign status.' data: message: id: 123 reference: order-1042 status: paused total_recipients: 1 queued_count: 1 sent_count: 0 failed_count: 0 created_at: '2026-09-12T10:00:00+00:00' completed_at: null queue: success: false campaign_id: 123 message: 'Queue dispatch could not be confirmed. Review this campaign before resuming.' 409: description: 'Still processing' content: application/json: schema: type: object properties: message: type: string examples: - 'A request with this Idempotency-Key is still being processed. Retry with the same key shortly.' examples: - message: 'A request with this Idempotency-Key is still being processed. Retry with the same key shortly.' 422: description: 'Validation error' content: application/json: schema: type: object properties: message: type: string examples: - 'The given data was invalid.' errors: type: object properties: recipients: type: array items: type: string examples: - - 'The recipients field is required.' examples: - message: 'The given data was invalid.' errors: recipients: - 'The recipients field is required.' tags: - 'Developer SMS' requestBody: required: true content: application/json: schema: type: object properties: recipients: type: array description: '1–1,000 distinct phone numbers in E.164 format.' items: type: string examples: - - '+61400000000' message: type: string description: 'SMS content, 1–1,600 characters. For marketing, use {opt_out_url} once to choose the opt-out link position.' examples: - 'Your order 1042 is confirmed.' message_purpose: type: - string - 'null' description: 'Defaults to transactional.' enum: - transactional - marketing examples: - transactional sender_id: type: - string - 'null' description: 'Up to 11 letters, digits, or spaces. Required when the selected provider requires a sender ID.' examples: - null routing_type: type: - string - 'null' description: "Direct uses one provider; failover uses an enabled route. Omit all routing fields to use the key's routing." enum: - direct - failover examples: - null provider_slug: type: - string - 'null' description: 'Active provider slug. Direct routing without a provider slug selects IntelliSend.' examples: - null failover_route_slug: type: - string - 'null' description: 'Required only when routing_type is failover; omit provider_slug in that case.' examples: - null reference: type: - string - 'null' description: 'Customer reference, up to 100 characters, stored with the campaign.' examples: - order-1042 required: - recipients - message '/api/v1/messages/{campaign}': get: summary: 'Get message status' operationId: getMessageStatus description: "Requires the `messages:read` ability and access to the campaign. Returns the campaign's current send counters.\n\n`sent_count` means provider submission, not confirmed handset delivery. Use [webhooks](#webhooks) for delivery updates where supported. Use this endpoint to inspect a send that returned `data.queue.success: false`." parameters: [] responses: 200: description: Completed content: application/json: schema: type: object properties: data: type: object properties: message: type: object properties: id: type: integer description: 'Campaign ID returned by the send endpoint.' examples: - 123 reference: type: string description: 'Your customer reference, or null.' examples: - order-1042 status: type: string description: 'Current campaign processing status.' examples: - completed total_recipients: type: integer description: 'Number of recipients recorded on the campaign.' examples: - 1 queued_count: type: integer description: 'Messages currently queued.' examples: - 0 sent_count: type: integer description: 'Messages submitted to a provider, not confirmed handset deliveries.' examples: - 1 failed_count: type: integer description: 'Messages that failed to send.' examples: - 0 created_at: type: string description: 'ISO 8601 creation timestamp.' examples: - '2026-09-12T10:00:00+00:00' completed_at: type: string description: 'ISO 8601 completion timestamp, or null while incomplete.' examples: - '2026-09-12T10:00:03+00:00' examples: - data: message: id: 123 reference: order-1042 status: completed total_recipients: 1 queued_count: 0 sent_count: 1 failed_count: 0 created_at: '2026-09-12T10:00:00+00:00' completed_at: '2026-09-12T10:00:03+00:00' 404: description: 'Not found' content: application/json: schema: type: object properties: title: type: string examples: - 'Resource not found' detail: type: string examples: - 'The requested resource was not found' instance: type: string examples: - 'https://your-workspace.example/api/v1/messages/123' code: type: string examples: - NOT-404 link: type: string examples: - '' examples: - title: 'Resource not found' detail: 'The requested resource was not found' instance: 'https://your-workspace.example/api/v1/messages/123' code: NOT-404 link: '' tags: - 'Developer SMS' parameters: - in: path name: campaign description: 'IntelliSend campaign ID.' required: true schema: type: integer examples: - 123 /api/v1/otp/send: post: summary: 'Send OTP' operationId: sendOTP description: "Requires the `otp:send` ability. Sends through IntelliSend using tenant credits, or a connected customer-funded provider. An approved custom sender or the tenant's configured IntelliSend sender can be used.\n\nThe API stores only the code hash and never returns the plaintext code. A new code invalidates the previous code for the same user, recipient, and purpose. Use the same Idempotency-Key when retrying this send. See [provider requirements](#routing).\n\nUse service_slug to load a saved OTP service's current settings, or provide purpose and optional settings explicitly. Do not mix service_slug with purpose, code_length, expires_in_minutes, template_slug, message_template, provider_slug, sender_id, routing_type, or failover_route_slug. See the [OTP service guide](#otp). Save data.request_id to verify independently of later service edits." parameters: - in: header name: Idempotency-Key description: '' schema: type: string examples: - otp-20260912-001 responses: 202: description: Submitted content: application/json: schema: type: object properties: message: type: string examples: - 'OTP submitted.' data: type: object properties: request_id: type: string description: 'Stable OTP request identifier.' examples: - 0195f79a-c230-748b-b868-2792aa113579 status: type: string description: 'accepted, pending, or failed. Pending means acceptance is uncertain; retry the same Idempotency-Key to check without resending.' examples: - accepted expires_at: type: string description: 'ISO 8601 timestamp after which the code cannot be verified.' examples: - '2026-09-24T12:05:00+00:00' provider: type: string description: 'Slug of the provider that accepted the submission.' examples: - intellisend sender_id: type: string description: 'Actual registered sender selected for this request, or null for the connected provider default.' examples: - '61485900180' billing: type: object properties: source: type: string examples: - intellisend_credits status: type: string examples: - charged credits_charged: type: integer examples: - 1 description: 'Billing source, settlement status, and net IntelliSend credits charged. Connected-provider charges are external.' examples: - message: 'OTP submitted.' data: request_id: 0195f79a-c230-748b-b868-2792aa113579 status: accepted expires_at: '2026-09-24T12:05:00+00:00' provider: intellisend sender_id: '61485900180' billing: source: intellisend_credits status: charged credits_charged: 1 409: description: 'Still processing' content: application/json: schema: type: object properties: message: type: string examples: - 'A request with this Idempotency-Key is still being processed. Retry with the same key shortly.' examples: - message: 'A request with this Idempotency-Key is still being processed. Retry with the same key shortly.' 422: description: 'Validation error' content: application/json: schema: type: object properties: message: type: string examples: - 'The given data was invalid.' errors: type: object properties: recipient: type: array items: type: string examples: - - 'The recipient field is required.' examples: - message: 'The given data was invalid.' errors: recipient: - 'The recipient field is required.' tags: - 'Developer OTP' requestBody: required: true content: application/json: schema: type: object properties: recipient: type: string description: 'Recipient phone number in E.164 format.' examples: - '+61400000000' service_slug: type: - string - 'null' description: "UUID slug copied from More services → OTP. Loads settings from this organization's saved service. Omit explicit settings, provider, sender, and routing when using it." examples: - 0195f798-5a50-7bc7-a1b5-36e303be0024 purpose: type: - string - 'null' description: 'Required without service_slug; omit when using a service. Stable verification purpose, up to 100 letters, digits, dots, underscores, colons, or hyphens.' examples: - null code: type: string description: 'Forbidden in send requests. The server generates the code.' examples: - null template_slug: type: - string - 'null' description: 'Without service_slug: enabled transactional template in this organization. Requires message.read permission. Mutually exclusive with message_template.' examples: - null message_template: type: - string - 'null' description: 'Without service_slug: inline message with exactly one {code} and no other placeholders. Omit both template fields for "Your verification code is {code}.". Must fit one rendered SMS segment.' examples: - null code_length: type: - integer - 'null' description: 'Without service_slug: code length from 6 to 8; defaults to 6.' examples: - null expires_in_minutes: type: - integer - 'null' description: 'Without service_slug: lifetime from 1 to 10 minutes; defaults to 5.' examples: - null sender_id: type: - string - 'null' description: 'Without service_slug: registered sender name or number, up to 50 characters. Omit for the configured IntelliSend sender. Custom senders must be approved and belong to this tenant and provider.' examples: - null routing_type: type: - string - 'null' description: 'Without service_slug: direct only. OTP does not support failover.' enum: - direct examples: - null provider_slug: type: - string - 'null' description: "Without service_slug: active SMS provider slug. Omit routing fields to use the key's direct provider, then IntelliSend by default. IntelliSend supports Australian mobile numbers." examples: - null failover_route_slug: type: string description: 'Forbidden for OTP. Select one provider or a saved service.' examples: - null required: - recipient /api/v1/otp/verify: post: summary: 'Verify OTP' operationId: verifyOTP description: "Requires the `otp:verify` ability. Use the same user and recipient as the send request, with its returned request_id. Existing integrations can supply the original purpose instead. Never supply both selectors.\n\nA code is valid once only. It is rejected after expiry or five failed verification attempts within 15 minutes. Resending does not reset that count. Send the code as a string to preserve leading zeroes." parameters: [] responses: 200: description: Verified content: application/json: schema: type: object properties: message: type: string description: 'Verification result. Invalid, expired, or exhausted codes share the same failure message.' examples: - 'OTP verified.' examples: - message: 'OTP verified.' 422: description: 'Invalid or expired code' content: application/json: schema: type: object properties: message: type: string description: 'Verification result. Invalid, expired, or exhausted codes share the same failure message.' examples: - 'The verification code is invalid or expired.' examples: - message: 'The verification code is invalid or expired.' tags: - 'Developer OTP' requestBody: required: true content: application/json: schema: type: object properties: recipient: type: string description: 'Recipient phone number in E.164 format.' examples: - '+61400000000' purpose: type: - string - 'null' description: 'Required without request_id. The original purpose at send time; omit when verifying by request_id.' examples: - null request_id: type: - string - 'null' description: 'The data.request_id returned by send. Recommended for saved services; remains valid after service edits or deletion. Mutually exclusive with purpose.' examples: - 0195f79a-c230-748b-b868-2792aa113579 code: type: string description: 'Numeric verification code, 4–8 digits. Preserve leading zeroes.' examples: - '012345' required: - recipient - code