{
    "openapi": "3.1.0",
    "info": {
        "title": "SMSend Public API",
        "version": "v1",
        "description": "The SMSend published API. REST, versioned in the URL, authenticated with a scoped API key.\n\n## Two obligations on your client\n\nThese are part of the contract, not advice. We rely on both when shipping non-breaking changes.\n\n1. **Tolerate unknown fields.** We add optional fields to responses and webhook payloads without a\n   version bump. A client that rejects an unrecognised key will break on a release that broke nobody else.\n2. **Tolerate unknown enum values.** We add values to `status`, `reason_code` and event types without a\n   version bump. Switch with a default branch; never assume the set you can see today is the whole set.\n\n## Partial acceptance is a success\n\nA submission where some recipients were filtered returns **202**, not an error. Read `accepted`,\n`rejected` and `rejections` \u2014 never branch on the HTTP status alone. A client that treats 202 as\n\"all recipients accepted\" will be permanently wrong by however many were dropped.\n\n## Idempotency\n\n`Idempotency-Key` is **required** on `POST /batches`, and is scoped to your API key. Retrying with the\nsame key and the same body replays the original response. Retrying with the same key and a *different*\nbody is refused with `IDEMPOTENCY_KEY_REUSED` \u2014 we will never silently return someone else's batch.\nA request still in flight answers `REQUEST_IN_PROGRESS` with `Retry-After`.\n\n## Two rate limits, and which fires first\n\n- **Per key, per request.** Enforced before anything is parsed. Exceeding it returns `429` with\n  `Retry-After` and `X-RateLimit-*` headers, and **nothing happened** \u2014 a 429'd request consumes none\n  of your account's send allowance, because no batch was submitted.\n- **Per account, per recipient.** Enforced inside an accepted submission. Exceeding it does not fail\n  the request: individual recipients are dropped and reported in `rejections` with the reason code.\n\nThe first always fires before the second.",
        "contact": {
            "name": "SMSend support"
        }
    },
    "servers": [
        {
            "url": "https://api.smsend.net/public/v1"
        }
    ],
    "security": [
        {
            "ApiKeyAuth": []
        }
    ],
    "tags": [
        {
            "name": "Messaging",
            "description": "Submitting batches and reading their outcome."
        },
        {
            "name": "Account",
            "description": "Balance and sender identities."
        },
        {
            "name": "Webhooks",
            "description": "Endpoint registration, secret rotation, re-enabling."
        }
    ],
    "paths": {
        "/batches": {
            "post": {
                "tags": [
                    "Messaging"
                ],
                "summary": "Submit a batch",
                "description": "Accepts, prices and reserves a batch. Returns 202 with the partial-acceptance shape.",
                "x-required-scope": "MESSAGES_SEND",
                "parameters": [
                    {
                        "name": "Idempotency-Key",
                        "in": "header",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "maxLength": 255
                        },
                        "description": "Unique per submission, scoped to your key. Required."
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/SubmitBatchRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "202": {
                        "description": "Accepted. Read `rejected` and `rejections`: some recipients may have been filtered.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SubmitBatchResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "UNAUTHORIZED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "FORBIDDEN, INSUFFICIENT_SCOPE, ACCOUNT_SUSPENDED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "VALIDATION_FAILED, IDEMPOTENCY_KEY_REQUIRED, BATCH_EMPTY, BATCH_BODY_EMPTY, SCHEDULE_INVALID, SENDER_NOT_APPROVED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "NOT_FOUND",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "UNSUPPORTED_VERSION",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "REQUEST_IN_PROGRESS, IDEMPOTENCY_KEY_REUSED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "INSUFFICIENT_FUNDS, CREDIT_LIMIT_EXCEEDED, WALLET_IN_DEBIT",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "RATE_LIMITED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "CONFIGURATION_ERROR, INTERNAL_ERROR",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/batches/{batch_id}": {
            "get": {
                "tags": [
                    "Messaging"
                ],
                "summary": "Fetch a batch",
                "x-required-scope": "MESSAGES_READ",
                "parameters": [
                    {
                        "name": "batch_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "minLength": 26,
                            "maxLength": 26
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The batch, its counters and everything that was filtered.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Batch"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "UNAUTHORIZED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "FORBIDDEN, INSUFFICIENT_SCOPE, ACCOUNT_SUSPENDED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "VALIDATION_FAILED, IDEMPOTENCY_KEY_REQUIRED, BATCH_EMPTY, BATCH_BODY_EMPTY, SCHEDULE_INVALID, SENDER_NOT_APPROVED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "NOT_FOUND",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "UNSUPPORTED_VERSION",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "REQUEST_IN_PROGRESS, IDEMPOTENCY_KEY_REUSED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "INSUFFICIENT_FUNDS, CREDIT_LIMIT_EXCEEDED, WALLET_IN_DEBIT",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "RATE_LIMITED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "CONFIGURATION_ERROR, INTERNAL_ERROR",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/messages/{message_id}": {
            "get": {
                "tags": [
                    "Messaging"
                ],
                "summary": "Fetch a message",
                "x-required-scope": "MESSAGES_READ",
                "parameters": [
                    {
                        "name": "message_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "minLength": 26,
                            "maxLength": 26
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "One message.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Message"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "UNAUTHORIZED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "FORBIDDEN, INSUFFICIENT_SCOPE, ACCOUNT_SUSPENDED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "VALIDATION_FAILED, IDEMPOTENCY_KEY_REQUIRED, BATCH_EMPTY, BATCH_BODY_EMPTY, SCHEDULE_INVALID, SENDER_NOT_APPROVED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "NOT_FOUND",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "UNSUPPORTED_VERSION",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "REQUEST_IN_PROGRESS, IDEMPOTENCY_KEY_REUSED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "INSUFFICIENT_FUNDS, CREDIT_LIMIT_EXCEEDED, WALLET_IN_DEBIT",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "RATE_LIMITED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "CONFIGURATION_ERROR, INTERNAL_ERROR",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/messages": {
            "get": {
                "tags": [
                    "Messaging"
                ],
                "summary": "Catch up on status changes",
                "description": "Everything whose status changed at or after `status_changed_since`, oldest first. This is how you recover events after a webhook outage: poll from the moment your endpoint last answered, then follow `next_status_changed_since` until `has_more` is false.",
                "x-required-scope": "MESSAGES_READ",
                "parameters": [
                    {
                        "name": "status_changed_since",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date-time"
                        },
                        "description": "ISO-8601. Clamped to the maximum lookback rather than refused."
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "default": 100,
                            "maximum": 500
                        }
                    },
                    {
                        "name": "batch_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of messages, plus the cursor to resume from.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/MessagePage"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "UNAUTHORIZED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "FORBIDDEN, INSUFFICIENT_SCOPE, ACCOUNT_SUSPENDED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "VALIDATION_FAILED, IDEMPOTENCY_KEY_REQUIRED, BATCH_EMPTY, BATCH_BODY_EMPTY, SCHEDULE_INVALID, SENDER_NOT_APPROVED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "NOT_FOUND",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "UNSUPPORTED_VERSION",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "REQUEST_IN_PROGRESS, IDEMPOTENCY_KEY_REUSED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "INSUFFICIENT_FUNDS, CREDIT_LIMIT_EXCEEDED, WALLET_IN_DEBIT",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "RATE_LIMITED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "CONFIGURATION_ERROR, INTERNAL_ERROR",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/account/balance": {
            "get": {
                "tags": [
                    "Account"
                ],
                "summary": "Account balance",
                "description": "Alarm on `spendable`, not on `balance`: a postpaid account runs at or below zero by design and its headroom is the credit limit underneath it.",
                "x-required-scope": "ACCOUNT_READ",
                "responses": {
                    "200": {
                        "description": "Whole XOF.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Balance"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "UNAUTHORIZED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "FORBIDDEN, INSUFFICIENT_SCOPE, ACCOUNT_SUSPENDED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "VALIDATION_FAILED, IDEMPOTENCY_KEY_REQUIRED, BATCH_EMPTY, BATCH_BODY_EMPTY, SCHEDULE_INVALID, SENDER_NOT_APPROVED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "NOT_FOUND",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "UNSUPPORTED_VERSION",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "REQUEST_IN_PROGRESS, IDEMPOTENCY_KEY_REUSED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "INSUFFICIENT_FUNDS, CREDIT_LIMIT_EXCEEDED, WALLET_IN_DEBIT",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "RATE_LIMITED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "CONFIGURATION_ERROR, INTERNAL_ERROR",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/sender-ids": {
            "get": {
                "tags": [
                    "Account"
                ],
                "summary": "Sender identities",
                "description": "Check `is_sendable`, not `status`. A sender approved by SMSend but not yet registered with an operator cannot be used, and submitting with it fails every message.",
                "x-required-scope": "SENDER_IDS_READ",
                "responses": {
                    "200": {
                        "description": "Every sender this account has requested.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SenderIdList"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "UNAUTHORIZED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "FORBIDDEN, INSUFFICIENT_SCOPE, ACCOUNT_SUSPENDED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "VALIDATION_FAILED, IDEMPOTENCY_KEY_REQUIRED, BATCH_EMPTY, BATCH_BODY_EMPTY, SCHEDULE_INVALID, SENDER_NOT_APPROVED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "NOT_FOUND",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "UNSUPPORTED_VERSION",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "REQUEST_IN_PROGRESS, IDEMPOTENCY_KEY_REUSED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "INSUFFICIENT_FUNDS, CREDIT_LIMIT_EXCEEDED, WALLET_IN_DEBIT",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "RATE_LIMITED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "CONFIGURATION_ERROR, INTERNAL_ERROR",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/webhooks": {
            "get": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "List endpoints",
                "x-required-scope": "WEBHOOKS_MANAGE",
                "responses": {
                    "200": {
                        "description": "Your endpoints. Secrets are never returned by a read."
                    },
                    "401": {
                        "description": "UNAUTHORIZED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "FORBIDDEN, INSUFFICIENT_SCOPE, ACCOUNT_SUSPENDED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "VALIDATION_FAILED, IDEMPOTENCY_KEY_REQUIRED, BATCH_EMPTY, BATCH_BODY_EMPTY, SCHEDULE_INVALID, SENDER_NOT_APPROVED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "NOT_FOUND",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "UNSUPPORTED_VERSION",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "REQUEST_IN_PROGRESS, IDEMPOTENCY_KEY_REUSED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "INSUFFICIENT_FUNDS, CREDIT_LIMIT_EXCEEDED, WALLET_IN_DEBIT",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "RATE_LIMITED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "CONFIGURATION_ERROR, INTERNAL_ERROR",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Register an endpoint",
                "description": "The response is the only time the signing secret is returned. Store it.",
                "x-required-scope": "WEBHOOKS_MANAGE",
                "responses": {
                    "201": {
                        "description": "Created, with the signing secret."
                    },
                    "401": {
                        "description": "UNAUTHORIZED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "FORBIDDEN, INSUFFICIENT_SCOPE, ACCOUNT_SUSPENDED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "VALIDATION_FAILED, IDEMPOTENCY_KEY_REQUIRED, BATCH_EMPTY, BATCH_BODY_EMPTY, SCHEDULE_INVALID, SENDER_NOT_APPROVED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "NOT_FOUND",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "UNSUPPORTED_VERSION",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "REQUEST_IN_PROGRESS, IDEMPOTENCY_KEY_REUSED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "INSUFFICIENT_FUNDS, CREDIT_LIMIT_EXCEEDED, WALLET_IN_DEBIT",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "RATE_LIMITED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "CONFIGURATION_ERROR, INTERNAL_ERROR",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/webhooks/{webhook_id}/rotate": {
            "post": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Rotate the signing secret",
                "description": "The previous secret keeps verifying for 24 hours, so you can deploy the new one without a window in which deliveries fail.",
                "x-required-scope": "WEBHOOKS_MANAGE",
                "responses": {
                    "200": {
                        "description": "The new secret, and when the old one stops working."
                    },
                    "401": {
                        "description": "UNAUTHORIZED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "FORBIDDEN, INSUFFICIENT_SCOPE, ACCOUNT_SUSPENDED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "VALIDATION_FAILED, IDEMPOTENCY_KEY_REQUIRED, BATCH_EMPTY, BATCH_BODY_EMPTY, SCHEDULE_INVALID, SENDER_NOT_APPROVED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "NOT_FOUND",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "UNSUPPORTED_VERSION",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "REQUEST_IN_PROGRESS, IDEMPOTENCY_KEY_REUSED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "INSUFFICIENT_FUNDS, CREDIT_LIMIT_EXCEEDED, WALLET_IN_DEBIT",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "RATE_LIMITED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "CONFIGURATION_ERROR, INTERNAL_ERROR",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/webhooks/{webhook_id}/enable": {
            "post": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Re-enable an endpoint",
                "description": "We never re-enable an auto-disabled endpoint for you. Recover the events you missed with GET /messages?status_changed_since=.",
                "x-required-scope": "WEBHOOKS_MANAGE",
                "responses": {
                    "200": {
                        "description": "Enabled; the failure counter is reset."
                    },
                    "401": {
                        "description": "UNAUTHORIZED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "FORBIDDEN, INSUFFICIENT_SCOPE, ACCOUNT_SUSPENDED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "VALIDATION_FAILED, IDEMPOTENCY_KEY_REQUIRED, BATCH_EMPTY, BATCH_BODY_EMPTY, SCHEDULE_INVALID, SENDER_NOT_APPROVED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "NOT_FOUND",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "UNSUPPORTED_VERSION",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "REQUEST_IN_PROGRESS, IDEMPOTENCY_KEY_REUSED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "INSUFFICIENT_FUNDS, CREDIT_LIMIT_EXCEEDED, WALLET_IN_DEBIT",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "RATE_LIMITED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "CONFIGURATION_ERROR, INTERNAL_ERROR",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/webhooks/{webhook_id}/disable": {
            "post": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Disable an endpoint",
                "x-required-scope": "WEBHOOKS_MANAGE",
                "responses": {
                    "200": {
                        "description": "Disabled."
                    },
                    "401": {
                        "description": "UNAUTHORIZED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "FORBIDDEN, INSUFFICIENT_SCOPE, ACCOUNT_SUSPENDED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "VALIDATION_FAILED, IDEMPOTENCY_KEY_REQUIRED, BATCH_EMPTY, BATCH_BODY_EMPTY, SCHEDULE_INVALID, SENDER_NOT_APPROVED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "NOT_FOUND",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "UNSUPPORTED_VERSION",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "REQUEST_IN_PROGRESS, IDEMPOTENCY_KEY_REUSED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "INSUFFICIENT_FUNDS, CREDIT_LIMIT_EXCEEDED, WALLET_IN_DEBIT",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "RATE_LIMITED",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "CONFIGURATION_ERROR, INTERNAL_ERROR",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "ApiKeyAuth": {
                "type": "http",
                "scheme": "bearer",
                "description": "Your key, as `Authorization: Bearer sk_live_\u2026.\u2026`. `X-API-Key` is accepted as an alternative for gateways that rewrite `Authorization`. Never send a key in a query string."
            }
        },
        "schemas": {
            "SubmitBatchRequest": {
                "type": "object",
                "required": [
                    "sender",
                    "body",
                    "message_class",
                    "recipients"
                ],
                "properties": {
                    "sender": {
                        "type": "string",
                        "maxLength": 32
                    },
                    "body": {
                        "type": "string",
                        "maxLength": 4000,
                        "description": "May contain {tag} merge tags."
                    },
                    "message_class": {
                        "type": "string",
                        "enum": [
                            "TRANSACTIONAL",
                            "MARKETING",
                            "OTP"
                        ]
                    },
                    "channel": {
                        "type": "string",
                        "enum": [
                            "SMS",
                            "WHATSAPP"
                        ]
                    },
                    "recipients": {
                        "type": "array",
                        "minItems": 1,
                        "items": {
                            "type": "object",
                            "required": [
                                "msisdn"
                            ],
                            "properties": {
                                "msisdn": {
                                    "type": "string"
                                },
                                "attributes": {
                                    "type": "object",
                                    "description": "Merge-tag values for this recipient."
                                }
                            }
                        }
                    },
                    "scheduled_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "timezone": {
                        "type": "string",
                        "description": "IANA name. Defaults to the account timezone."
                    },
                    "is_test": {
                        "type": "boolean"
                    }
                }
            },
            "SubmitBatchResponse": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "batch_id": {
                                "type": "string"
                            },
                            "status": {
                                "type": "string",
                                "enum": [
                                    "VALIDATING",
                                    "SCHEDULED",
                                    "QUEUED",
                                    "SENDING",
                                    "SETTLED",
                                    "REJECTED",
                                    "FAILED",
                                    "CANCELLED"
                                ]
                            },
                            "accepted": {
                                "type": "integer"
                            },
                            "rejected": {
                                "type": "integer"
                            },
                            "rejections": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/Rejection"
                                }
                            },
                            "reserved_amount": {
                                "type": "integer",
                                "description": "Whole XOF."
                            },
                            "currency": {
                                "type": "string"
                            },
                            "total_segments": {
                                "type": "integer"
                            }
                        }
                    }
                }
            },
            "Rejection": {
                "type": "object",
                "properties": {
                    "index": {
                        "type": "integer",
                        "description": "The recipient's position in your request."
                    },
                    "msisdn": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "reason_code": {
                        "type": "string"
                    }
                }
            },
            "Batch": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "batch_id": {
                                "type": "string"
                            },
                            "status": {
                                "type": "string",
                                "enum": [
                                    "VALIDATING",
                                    "SCHEDULED",
                                    "QUEUED",
                                    "SENDING",
                                    "SETTLED",
                                    "REJECTED",
                                    "FAILED",
                                    "CANCELLED"
                                ]
                            },
                            "accepted": {
                                "type": "integer"
                            },
                            "rejected": {
                                "type": "integer"
                            },
                            "rejections": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/Rejection"
                                }
                            },
                            "counts": {
                                "type": "object"
                            }
                        }
                    }
                }
            },
            "Message": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "message_id": {
                                "type": "string"
                            },
                            "batch_id": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "msisdn": {
                                "type": "string"
                            },
                            "status": {
                                "type": "string",
                                "enum": [
                                    "SCHEDULED",
                                    "QUEUED",
                                    "RETRY_SCHEDULED",
                                    "SUBMITTED",
                                    "SENT",
                                    "DELIVERED",
                                    "FAILED",
                                    "EXPIRED",
                                    "REJECTED",
                                    "CANCELLED"
                                ],
                                "description": "New values may be added without a version bump. Handle unknown values."
                            },
                            "segments": {
                                "type": "integer"
                            },
                            "status_changed_at": {
                                "type": "string",
                                "format": "date-time",
                                "description": "The cursor for GET /messages?status_changed_since=."
                            }
                        }
                    }
                }
            },
            "MessagePage": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "messages": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "properties": {
                                        "message_id": {
                                            "type": "string"
                                        },
                                        "batch_id": {
                                            "type": [
                                                "string",
                                                "null"
                                            ]
                                        },
                                        "msisdn": {
                                            "type": "string"
                                        },
                                        "status": {
                                            "type": "string",
                                            "enum": [
                                                "SCHEDULED",
                                                "QUEUED",
                                                "RETRY_SCHEDULED",
                                                "SUBMITTED",
                                                "SENT",
                                                "DELIVERED",
                                                "FAILED",
                                                "EXPIRED",
                                                "REJECTED",
                                                "CANCELLED"
                                            ],
                                            "description": "New values may be added without a version bump. Handle unknown values."
                                        },
                                        "segments": {
                                            "type": "integer"
                                        },
                                        "status_changed_at": {
                                            "type": "string",
                                            "format": "date-time",
                                            "description": "The cursor for GET /messages?status_changed_since=."
                                        }
                                    }
                                }
                            },
                            "has_more": {
                                "type": "boolean"
                            },
                            "next_status_changed_since": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "format": "date-time"
                            }
                        }
                    }
                }
            },
            "Balance": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "account_id": {
                                "type": "string"
                            },
                            "billing_mode": {
                                "type": "string"
                            },
                            "balance": {
                                "type": "integer"
                            },
                            "spendable": {
                                "type": "integer"
                            },
                            "credit_limit": {
                                "type": "integer"
                            },
                            "currency": {
                                "type": "string"
                            }
                        }
                    }
                }
            },
            "SenderIdList": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "sender_ids": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "properties": {
                                        "sender_id": {
                                            "type": "string"
                                        },
                                        "value": {
                                            "type": "string"
                                        },
                                        "status": {
                                            "type": "string"
                                        },
                                        "is_sendable": {
                                            "type": "boolean"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "Error": {
                "type": "object",
                "properties": {
                    "error": {
                        "type": "object",
                        "properties": {
                            "code": {
                                "type": "string",
                                "enum": [
                                    "UNAUTHORIZED",
                                    "FORBIDDEN",
                                    "INSUFFICIENT_SCOPE",
                                    "ACCOUNT_SUSPENDED",
                                    "VALIDATION_FAILED",
                                    "NOT_FOUND",
                                    "UNSUPPORTED_VERSION",
                                    "IDEMPOTENCY_KEY_REQUIRED",
                                    "REQUEST_IN_PROGRESS",
                                    "IDEMPOTENCY_KEY_REUSED",
                                    "INSUFFICIENT_FUNDS",
                                    "CREDIT_LIMIT_EXCEEDED",
                                    "WALLET_IN_DEBIT",
                                    "BATCH_EMPTY",
                                    "BATCH_BODY_EMPTY",
                                    "SCHEDULE_INVALID",
                                    "SENDER_NOT_APPROVED",
                                    "RATE_LIMITED",
                                    "CONFIGURATION_ERROR",
                                    "INTERNAL_ERROR"
                                ]
                            },
                            "message": {
                                "type": "string"
                            },
                            "retryable": {
                                "type": "boolean"
                            },
                            "detail": {
                                "type": "object"
                            },
                            "request_id": {
                                "type": "string",
                                "description": "Quote this to support."
                            }
                        }
                    }
                }
            }
        }
    },
    "x-smsend-error-codes": [
        {
            "code": "UNAUTHORIZED",
            "http_status": 401,
            "retryable": false
        },
        {
            "code": "FORBIDDEN",
            "http_status": 403,
            "retryable": false
        },
        {
            "code": "INSUFFICIENT_SCOPE",
            "http_status": 403,
            "retryable": false
        },
        {
            "code": "ACCOUNT_SUSPENDED",
            "http_status": 403,
            "retryable": false
        },
        {
            "code": "VALIDATION_FAILED",
            "http_status": 422,
            "retryable": false
        },
        {
            "code": "NOT_FOUND",
            "http_status": 404,
            "retryable": false
        },
        {
            "code": "UNSUPPORTED_VERSION",
            "http_status": 400,
            "retryable": false
        },
        {
            "code": "IDEMPOTENCY_KEY_REQUIRED",
            "http_status": 422,
            "retryable": false
        },
        {
            "code": "REQUEST_IN_PROGRESS",
            "http_status": 409,
            "retryable": true
        },
        {
            "code": "IDEMPOTENCY_KEY_REUSED",
            "http_status": 409,
            "retryable": false
        },
        {
            "code": "INSUFFICIENT_FUNDS",
            "http_status": 402,
            "retryable": false
        },
        {
            "code": "CREDIT_LIMIT_EXCEEDED",
            "http_status": 402,
            "retryable": false
        },
        {
            "code": "WALLET_IN_DEBIT",
            "http_status": 402,
            "retryable": false
        },
        {
            "code": "BATCH_EMPTY",
            "http_status": 422,
            "retryable": false
        },
        {
            "code": "BATCH_BODY_EMPTY",
            "http_status": 422,
            "retryable": false
        },
        {
            "code": "SCHEDULE_INVALID",
            "http_status": 422,
            "retryable": false
        },
        {
            "code": "SENDER_NOT_APPROVED",
            "http_status": 422,
            "retryable": false
        },
        {
            "code": "RATE_LIMITED",
            "http_status": 429,
            "retryable": true
        },
        {
            "code": "CONFIGURATION_ERROR",
            "http_status": 500,
            "retryable": false
        },
        {
            "code": "INTERNAL_ERROR",
            "http_status": 500,
            "retryable": true
        }
    ],
    "x-smsend-webhooks": {
        "signature": {
            "header": "X-SMSend-Signature",
            "format": "t=<unix seconds>,v1=<hex hmac-sha256>",
            "signed_payload": "\"{t}.\" + the raw request body, byte for byte",
            "algorithm": "HMAC-SHA256, keyed with your endpoint secret",
            "tolerance_seconds": 300,
            "instructions": "Verify over the RAW body before parsing it. Reject anything whose `t` is more than 300 seconds from your clock, and compare digests in constant time. During a secret rotation, accept EITHER the new secret or the previous one until the rotation window closes \u2014 we always sign with the new one."
        },
        "ordering": {
            "field": "sequence",
            "guarantee": "Monotonic per endpoint. We do NOT guarantee delivery order: a retried delivery genuinely arrives after events created later than it.",
            "contract": "Ignore any event whose `sequence` is lower than the last you processed for that message."
        },
        "delivery": {
            "success": "Any 2xx. Redirects are not followed and do not count as delivered.",
            "max_attempts": 6,
            "backoff_seconds": [
                60,
                300,
                900,
                3600,
                14400
            ],
            "after_exhaustion": "The event is dropped. Recover it with GET /messages?status_changed_since=.",
            "auto_disable_after": 20,
            "auto_disable_note": "20 consecutive failures disables the endpoint and emails the account. Any success resets the counter. We never re-enable it for you."
        },
        "events": [
            {
                "type": "MESSAGE_TERMINAL",
                "default": true
            },
            {
                "type": "MESSAGE_STATUS_CHANGED",
                "default": false
            },
            {
                "type": "BATCH_SETTLED",
                "default": true
            },
            {
                "type": "BATCH_ACCEPTED",
                "default": false
            }
        ],
        "note_on_money": "MESSAGE_TERMINAL deliberately carries no refund field. Refunds are posted per batch when the batch settles, which is later than any single message going terminal; the figure is on BATCH_SETTLED, where it is final."
    },
    "x-smsend-versioning": {
        "current": "v1",
        "supported": [
            "v1"
        ],
        "policy": "The previous major version stays available alongside the current one. A version being withdrawn is announced at least 183 days in advance, its responses carry `Deprecation` and `Sunset` headers for the whole notice period, and every account whose key has called it in the last 90 days is emailed.",
        "breaking_changes": [
            "Removing or renaming a field",
            "Tightening validation",
            "Changing an error code"
        ],
        "non_breaking_changes": [
            "Adding an optional field",
            "Adding an enum value",
            "Adding an endpoint"
        ]
    }
}