{
    "openapi": "3.1.0",
    "info": {
        "title": "DezSMS API",
        "version": "1.0.0",
        "description": "REST API behind the DezSMS mobile app. Every response uses the same envelope (`success`, `message`, `data`, `meta`, `code`). Log in with `POST \/v1\/auth\/login` and `\/v1\/auth\/login\/verify`, then send the token as `Authorization: Bearer <token>`. Send `Accept-Language: ar` for Arabic messages."
    },
    "servers": [
        {
            "url": "https:\/\/api.dezsms.com\/api"
        }
    ],
    "security": [
        {
            "http": []
        }
    ],
    "paths": {
        "\/v1\/me": {
            "get": {
                "operationId": "account.show",
                "summary": "The logged-in member",
                "tags": [
                    "Account"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            },
            "patch": {
                "operationId": "account.update",
                "description": "Name, email and company (same fields as the website's profile page).\nThe mobile number is the login and can't be changed.",
                "summary": "Update profile",
                "tags": [
                    "Account"
                ],
                "requestBody": {
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/UpdateProfileRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                }
            },
            "delete": {
                "operationId": "account.destroy",
                "description": "Needs the website password. Deactivates the member and logs out every\ndevice; no data is removed. Logging in then fails with `account_inactive`,\nand only DezSMS support can reactivate the account.\nErrors: `wrong_password` (422).",
                "summary": "Delete account",
                "tags": [
                    "Account"
                ],
                "parameters": [
                    {
                        "name": "current_password",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/me\/password": {
            "post": {
                "operationId": "account.changePassword",
                "description": "The password is only used to log in on dezsms.com.",
                "summary": "Change website password",
                "tags": [
                    "Account"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/ChangePasswordRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                }
            }
        },
        "\/v1\/me\/picture": {
            "post": {
                "operationId": "account.uploadPicture",
                "description": "JPEG, PNG or WebP up to 1 MB, as multipart field `picture`. Replaces the\nold one. The website's profile page shows the same picture.",
                "summary": "Upload profile picture",
                "tags": [
                    "Account"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "multipart\/form-data": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "picture": {
                                        "type": "string",
                                        "format": "binary",
                                        "contentMediaType": "application\/octet-stream",
                                        "description": "Maximum file size: 1024 kilobytes."
                                    }
                                },
                                "required": [
                                    "picture"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/dashboard": {
            "get": {
                "operationId": "account.dashboard",
                "description": "Profile and balance, totals, the 3 latest news items and the 5 latest messages.",
                "summary": "Home screen",
                "tags": [
                    "Account"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/auth\/login": {
            "post": {
                "operationId": "auth.login",
                "description": "Texts a 4-digit code to the account's mobile. Errors: `account_not_found`\n(404), `account_not_verified` (403 \u2014 call `register\/resend`),\n`account_inactive` (403), `code_recently_sent` (429).",
                "summary": "Send a login code",
                "tags": [
                    "Auth\n\nThe app logs in with mobile number + SMS code only. Sign-up also takes a\npassword",
                    " which is used on the website.",
                    "Auth"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/MobileRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                },
                "security": []
            }
        },
        "\/v1\/auth\/login\/verify": {
            "post": {
                "operationId": "auth.verifyLogin",
                "description": "Returns a bearer token for the `Authorization` header.",
                "summary": "Log in with the code",
                "tags": [
                    "Auth\n\nThe app logs in with mobile number + SMS code only. Sign-up also takes a\npassword",
                    " which is used on the website.",
                    "Auth"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/VerifyCodeRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                },
                "security": []
            }
        },
        "\/v1\/auth\/register": {
            "post": {
                "operationId": "auth.register",
                "description": "Creates an inactive account (2 free points, 10 days validity \u2014 like the\nwebsite) and texts an activation code. Errors: `mobile_taken` (409;\n`errors.can_verify` is true when the account only needs verifying),\n`email_taken` (409).",
                "summary": "Create an account",
                "tags": [
                    "Auth\n\nThe app logs in with mobile number + SMS code only. Sign-up also takes a\npassword",
                    " which is used on the website.",
                    "Auth"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/RegisterRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                },
                "security": []
            }
        },
        "\/v1\/auth\/register\/verify": {
            "post": {
                "operationId": "auth.verifyRegistration",
                "description": "Also accepts the activation code of a sign-up started on the website.\nReturns a bearer token.",
                "summary": "Activate the account with the code",
                "tags": [
                    "Auth\n\nThe app logs in with mobile number + SMS code only. Sign-up also takes a\npassword",
                    " which is used on the website.",
                    "Auth"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/VerifyCodeRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                },
                "security": []
            }
        },
        "\/v1\/auth\/register\/resend": {
            "post": {
                "operationId": "auth.resendRegistration",
                "summary": "Resend the activation code",
                "tags": [
                    "Auth\n\nThe app logs in with mobile number + SMS code only. Sign-up also takes a\npassword",
                    " which is used on the website.",
                    "Auth"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/MobileRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                },
                "security": []
            }
        },
        "\/v1\/auth\/logout": {
            "post": {
                "operationId": "auth.logout",
                "description": "Revokes the token used for this request.",
                "summary": "Log out",
                "tags": [
                    "Auth\n\nThe app logs in with mobile number + SMS code only. Sign-up also takes a\npassword",
                    " which is used on the website.",
                    "Auth"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/balance\/history": {
            "get": {
                "operationId": "balance.history",
                "summary": "Balance history, newest first",
                "tags": [
                    "Balance & payments\n\nThe balance is in points. Packages are bought with KNET through the\nwebsite's gateway or with MyFatoorah; prepaid cards and transfers work like on the website.",
                    "Balance"
                ],
                "parameters": [
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 100
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/packages": {
            "get": {
                "operationId": "balance.packages",
                "summary": "SMS packages with this member's price",
                "tags": [
                    "Balance & payments\n\nThe balance is in points. Packages are bought with KNET through the\nwebsite's gateway or with MyFatoorah; prepaid cards and transfers work like on the website.",
                    "Balance"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/payments": {
            "get": {
                "operationId": "balance.purchases",
                "summary": "Package purchases, newest first (listorderSMS.php)",
                "tags": [
                    "Balance & payments\n\nThe balance is in points. Packages are bought with KNET through the\nwebsite's gateway or with MyFatoorah; prepaid cards and transfers work like on the website.",
                    "Balance"
                ],
                "parameters": [
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 100
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/payments\/knet": {
            "post": {
                "operationId": "balance.buy",
                "description": "Returns `pay_url` to open in the browser. After paying, poll\nGET \/payments\/{order_id} until it is `paid` or `failed`.",
                "summary": "Buy a package with KNET",
                "tags": [
                    "Balance & payments\n\nThe balance is in points. Packages are bought with KNET through the\nwebsite's gateway or with MyFatoorah; prepaid cards and transfers work like on the website.",
                    "Balance"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/payments\/myfatoorah": {
            "post": {
                "operationId": "balance.buyMyFatoorah",
                "description": "Works like POST \/payments\/knet. The page lists the methods enabled on\nthe DezSMS account (cards, Apple Pay, KNET...).",
                "summary": "Buy a package with MyFatoorah",
                "tags": [
                    "Balance & payments\n\nThe balance is in points. Packages are bought with KNET through the\nwebsite's gateway or with MyFatoorah; prepaid cards and transfers work like on the website.",
                    "Balance"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/payments\/{orderId}": {
            "get": {
                "operationId": "balance.payment",
                "description": "`pending` until the payment's return page credits the member, then\n`paid` (with points and validity) or `failed`. A MyFatoorah order is\nalso checked with MyFatoorah, for buyers who closed the payment page.",
                "summary": "Payment status",
                "tags": [
                    "Balance & payments\n\nThe balance is in points. Packages are bought with KNET through the\nwebsite's gateway or with MyFatoorah; prepaid cards and transfers work like on the website.",
                    "Balance"
                ],
                "parameters": [
                    {
                        "name": "orderId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/payments\/card": {
            "post": {
                "operationId": "balance.redeemCard",
                "description": "16-digit card number (recharge.php \/ confirmre.php). Limited to 5\nattempts an hour.",
                "summary": "Redeem a prepaid card",
                "tags": [
                    "Balance & payments\n\nThe balance is in points. Packages are bought with KNET through the\nwebsite's gateway or with MyFatoorah; prepaid cards and transfers work like on the website.",
                    "Balance"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "card_number": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "card_number"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/balance\/transfer": {
            "post": {
                "operationId": "balance.transfer",
                "description": "To another DezSMS account by its mobile number (transfer.php).",
                "summary": "Transfer points",
                "tags": [
                    "Balance & payments\n\nThe balance is in points. Packages are bought with KNET through the\nwebsite's gateway or with MyFatoorah; prepaid cards and transfers work like on the website.",
                    "Balance"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "mobile": {
                                        "type": "string"
                                    },
                                    "points": {
                                        "type": "number",
                                        "examples": [
                                            200
                                        ],
                                        "maximum": 10000000
                                    }
                                },
                                "required": [
                                    "mobile",
                                    "points"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/config": {
            "get": {
                "operationId": "config.show",
                "description": "SMS length rules, point rates per network, support contacts and the\nminimum supported app version. Call on app start.",
                "summary": "App settings",
                "tags": [
                    "Config"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    }
                },
                "security": []
            }
        },
        "\/v1\/devices": {
            "post": {
                "operationId": "devices.store",
                "description": "Call after login and whenever Firebase gives a new token. Stored in the\nwebsite's gwc_members_device table, with the app's language (from\nAccept-Language) for news pushes. Call again when the language changes.",
                "summary": "Register a push token",
                "tags": [
                    "Devices & notifications",
                    "Devices"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "token": {
                                        "type": "string",
                                        "maxLength": 255
                                    },
                                    "platform": {
                                        "type": "string",
                                        "enum": [
                                            "android",
                                            "ios"
                                        ]
                                    }
                                },
                                "required": [
                                    "token",
                                    "platform"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            },
            "delete": {
                "operationId": "devices.destroy",
                "summary": "Remove a push token (on logout)",
                "tags": [
                    "Devices & notifications",
                    "Devices"
                ],
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "maxLength": 255
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/notifications": {
            "get": {
                "operationId": "devices.notifications",
                "summary": "In-app notifications, newest first",
                "tags": [
                    "Devices & notifications",
                    "Devices"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/notifications\/read": {
            "post": {
                "operationId": "devices.markRead",
                "summary": "Mark notifications read (all, or the given `ids`)",
                "tags": [
                    "Devices & notifications",
                    "Devices"
                ],
                "requestBody": {
                    "content": {
                        "application\/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "ids": {
                                        "type": [
                                            "array",
                                            "null"
                                        ],
                                        "items": {
                                            "type": "string"
                                        }
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/groups": {
            "get": {
                "operationId": "groups.index",
                "description": "With the number of saved numbers in each.",
                "summary": "List groups",
                "tags": [
                    "Groups"
                ],
                "parameters": [
                    {
                        "name": "search",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "maxLength": 100
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            },
            "post": {
                "operationId": "groups.store",
                "summary": "Create a group",
                "tags": [
                    "Groups"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/groups\/{id}": {
            "patch": {
                "operationId": "groups.update",
                "summary": "Rename a group",
                "tags": [
                    "Groups"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            },
            "delete": {
                "operationId": "groups.destroy",
                "summary": "Delete a group and its numbers",
                "tags": [
                    "Groups"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/groups\/{id}\/numbers": {
            "get": {
                "operationId": "groups.numbers",
                "description": "Paged, newest first. `search` matches the number or name.",
                "summary": "Numbers in a group",
                "tags": [
                    "Groups"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "search",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "maxLength": 100
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 100
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            },
            "post": {
                "operationId": "groups.addNumbers",
                "description": "`numbers` is a list of `{number, name}` objects or plain number strings.\nNumbers already in the group are skipped.",
                "summary": "Add numbers",
                "tags": [
                    "Groups"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "numbers": {
                                        "type": "array",
                                        "examples": [
                                            [
                                                {
                                                    "number": "94404010",
                                                    "name": "Ahmad"
                                                },
                                                "66123456"
                                            ]
                                        ],
                                        "items": {
                                            "type": "object",
                                            "properties": {
                                                "number": {
                                                    "type": "string",
                                                    "maxLength": 20
                                                },
                                                "name": {
                                                    "type": [
                                                        "string",
                                                        "null"
                                                    ],
                                                    "maxLength": 200
                                                }
                                            }
                                        },
                                        "minItems": 1,
                                        "maxItems": 10000
                                    }
                                },
                                "required": [
                                    "numbers"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/groups\/{id}\/import": {
            "post": {
                "operationId": "groups.import",
                "description": "Excel (.xlsx), CSV or TXT: number in the first column, optional name in\nthe second (same layout as the website's import). Rows that aren't\nnumbers \u2014 such as a header \u2014 are reported as invalid.",
                "summary": "Import numbers from a file",
                "tags": [
                    "Groups"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "multipart\/form-data": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "file": {
                                        "type": "string",
                                        "format": "binary",
                                        "contentMediaType": "application\/octet-stream",
                                        "description": "Maximum file size: 5120 kilobytes."
                                    }
                                },
                                "required": [
                                    "file"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/groups\/{id}\/export": {
            "get": {
                "operationId": "groups.export",
                "description": "CSV download (mobile, name), the same layout Import accepts.",
                "summary": "Export numbers",
                "tags": [
                    "Groups"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "text\/csv; charset=UTF-8": {
                                "schema": {
                                    "type": "string",
                                    "format": "binary"
                                }
                            }
                        },
                        "headers": {
                            "Transfer-Encoding": {
                                "required": true,
                                "schema": {
                                    "type": "string",
                                    "enum": [
                                        "chunked"
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/groups\/{id}\/numbers\/{numberId}": {
            "delete": {
                "operationId": "groups.removeNumber",
                "summary": "Remove a number from a group",
                "tags": [
                    "Groups"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "numberId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/knet\/return\/package\/{token}": {
            "get": {
                "operationId": "knet.return.package",
                "tags": [
                    "KnetReturn"
                ],
                "parameters": [
                    {
                        "name": "token",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    }
                },
                "security": []
            }
        },
        "\/knet\/return\/sender-id\/{token}": {
            "get": {
                "operationId": "knet.return.sender-id",
                "tags": [
                    "KnetReturn"
                ],
                "parameters": [
                    {
                        "name": "token",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    }
                },
                "security": []
            }
        },
        "\/myfatoorah\/return\/package\/{token}": {
            "get": {
                "operationId": "knet.return.mf-package",
                "tags": [
                    "KnetReturn"
                ],
                "parameters": [
                    {
                        "name": "token",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    }
                },
                "security": []
            }
        },
        "\/myfatoorah\/return\/sender-id\/{token}": {
            "get": {
                "operationId": "knet.return.mf-sender-id",
                "tags": [
                    "KnetReturn"
                ],
                "parameters": [
                    {
                        "name": "token",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    }
                },
                "security": []
            }
        },
        "\/v1\/reports\/summary": {
            "get": {
                "operationId": "reports.summary",
                "description": "Messages, recipients and points for a date range (default: last 30\ndays). `queued` are still waiting, `failed` only exists for\npersonalised messages; everything else was accepted by the gateway.",
                "summary": "Sending summary",
                "tags": [
                    "Messages",
                    "Reports"
                ],
                "parameters": [
                    {
                        "name": "from",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        },
                        "example": "2026-09-14"
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        },
                        "example": "2026-10-14"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/messages\/quote": {
            "post": {
                "operationId": "messages.quote",
                "description": "Same checks as sending, without charging. Use it to show the cost\nbefore the user taps Send.",
                "summary": "Price a message",
                "tags": [
                    "Messages\n\nMessages are queued exactly like the website's and sent by its crons.\nThere are no per-number delivery reports: a message is \"queued\" until\nthe gateway accepts it",
                    " then \"sent\". Personalised messages also report\n\"failed\" numbers (their points are refunded).",
                    "Messages"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/SendMessageRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                }
            }
        },
        "\/v1\/messages": {
            "post": {
                "operationId": "messages.store",
                "description": "To typed numbers and\/or groups. With {name} or {number} in the text\nevery recipient gets their own message. Errors: `insufficient_balance`\n(402, `errors.needed` \/ `errors.balance`), `balance_expired` (403),\n`invalid_sender`, `message_too_long`, `invalid_numbers` (422),\n`sending_disabled` (503).",
                "summary": "Send or schedule a message",
                "tags": [
                    "Messages\n\nMessages are queued exactly like the website's and sent by its crons.\nThere are no per-number delivery reports: a message is \"queued\" until\nthe gateway accepts it",
                    " then \"sent\". Personalised messages also report\n\"failed\" numbers (their points are refunded).",
                    "Messages"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/SendMessageRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                }
            },
            "get": {
                "operationId": "messages.index",
                "description": "Newest first. `status=scheduled` lists only messages waiting for their\nscheduled time; `from` \/ `to` (dates) limit it to that period.",
                "summary": "List messages",
                "tags": [
                    "Messages\n\nMessages are queued exactly like the website's and sent by its crons.\nThere are no per-number delivery reports: a message is \"queued\" until\nthe gateway accepts it",
                    " then \"sent\". Personalised messages also report\n\"failed\" numbers (their points are refunded).",
                    "Messages"
                ],
                "parameters": [
                    {
                        "name": "status",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "all",
                                "scheduled",
                                null
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 50
                        }
                    },
                    {
                        "name": "from",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        },
                        "example": "2026-09-14"
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        },
                        "example": "2026-10-14"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/messages\/{id}": {
            "get": {
                "operationId": "messages.show",
                "description": "Adds the split by network and, for personalised messages, the numbers\nthat failed.",
                "summary": "Message details",
                "tags": [
                    "Messages\n\nMessages are queued exactly like the website's and sent by its crons.\nThere are no per-number delivery reports: a message is \"queued\" until\nthe gateway accepts it",
                    " then \"sent\". Personalised messages also report\n\"failed\" numbers (their points are refunded).",
                    "Messages"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            },
            "delete": {
                "operationId": "messages.destroy",
                "description": "Only while it is still waiting (at least a minute before its time).\nThe points are refunded.",
                "summary": "Cancel a scheduled message",
                "tags": [
                    "Messages\n\nMessages are queued exactly like the website's and sent by its crons.\nThere are no per-number delivery reports: a message is \"queued\" until\nthe gateway accepts it",
                    " then \"sent\". Personalised messages also report\n\"failed\" numbers (their points are refunded).",
                    "Messages"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/messages\/{id}\/export": {
            "get": {
                "operationId": "messages.export",
                "description": "CSV download: mobile, network and status (scheduled, queued, sent,\nfailed or cancelled), plus the text each number got for personalised\nmessages.",
                "summary": "Export recipients",
                "tags": [
                    "Messages\n\nMessages are queued exactly like the website's and sent by its crons.\nThere are no per-number delivery reports: a message is \"queued\" until\nthe gateway accepts it",
                    " then \"sent\". Personalised messages also report\n\"failed\" numbers (their points are refunded).",
                    "Messages"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "text\/csv; charset=UTF-8": {
                                "schema": {
                                    "type": "string",
                                    "format": "binary"
                                }
                            }
                        },
                        "headers": {
                            "Transfer-Encoding": {
                                "required": true,
                                "schema": {
                                    "type": "string",
                                    "enum": [
                                        "chunked"
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/news": {
            "get": {
                "operationId": "news.index",
                "summary": "News, newest first, in the app's language",
                "tags": [
                    "News"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/news\/{id}": {
            "get": {
                "operationId": "news.show",
                "summary": "One news item",
                "tags": [
                    "News"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/sender-ids": {
            "get": {
                "operationId": "senderIds.index",
                "description": "`active` are the names this member can send from. `requests` are\nrequests for new names (status: `pending_payment`, `submitted`).",
                "summary": "My sender IDs",
                "tags": [
                    "Sender IDs",
                    "SenderIds"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/sender-ids\/requests": {
            "post": {
                "operationId": "senderIdRequests.store",
                "description": "Like request.php \/ siddez.php: with a balance of 3,500 points or more\nthe request fee is taken in points (`paid_with: points`); otherwise the\nresponse has a `pay_url` (35 KD) for KNET, or for MyFatoorah with\n`method: myfatoorah`. DezSMS staff then register the name with the\noperators.",
                "summary": "Request a new sender ID",
                "tags": [
                    "Sender IDs",
                    "SenderIdRequests"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "sender_id": {
                                        "type": "string",
                                        "description": "Up to 11 characters: English letters, digits, space, dot, dash, underscore. @example MyClinic",
                                        "pattern": "^[-_a-zA-Z0-9 .]+$",
                                        "maxLength": 11
                                    },
                                    "method": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "enum": [
                                            "knet",
                                            "myfatoorah",
                                            null
                                        ]
                                    }
                                },
                                "required": [
                                    "sender_id"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/messages\/template\/uploads": {
            "post": {
                "operationId": "templateSend.upload",
                "description": "Excel (.xlsx) or CSV. Row 1 is the header; the first column is the\nmobile number and the other columns fill the template's {fields} by\nheader name. Kept for 24 hours.",
                "summary": "Upload a recipients file",
                "tags": [
                    "Template messages\n\nSend a template to a file of recipients: upload the file",
                    " check it\nagainst the template (quote)",
                    " then send.",
                    "TemplateSend"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "multipart\/form-data": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "file": {
                                        "type": "string",
                                        "format": "binary",
                                        "contentMediaType": "application\/octet-stream",
                                        "description": "Maximum file size: 5120 kilobytes."
                                    }
                                },
                                "required": [
                                    "file"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/messages\/template\/quote": {
            "post": {
                "operationId": "templateSend.quote",
                "description": "Returns the cost, or the problems to fix: `missing_columns` (columns\nthe template needs), `file_errors` (`errors.rows` lists bad rows).",
                "summary": "Check a template against a file",
                "tags": [
                    "Template messages\n\nSend a template to a file of recipients: upload the file",
                    " check it\nagainst the template (quote)",
                    " then send.",
                    "TemplateSend"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/messages\/template": {
            "post": {
                "operationId": "templateSend.send",
                "summary": "Send or schedule a template to a file",
                "tags": [
                    "Template messages\n\nSend a template to a file of recipients: upload the file",
                    " check it\nagainst the template (quote)",
                    " then send.",
                    "TemplateSend"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "sender": {
                                        "type": "string",
                                        "maxLength": 50
                                    },
                                    "schedule_at": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "format": "date-time"
                                    }
                                },
                                "required": [
                                    "sender"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/templates": {
            "get": {
                "operationId": "templates.index",
                "summary": "List templates",
                "tags": [
                    "Templates\n\nSaved messages with {fields} (tbltemplates \u2014 shared with the website).",
                    "Templates"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            },
            "post": {
                "operationId": "templates.store",
                "summary": "Create a template",
                "tags": [
                    "Templates\n\nSaved messages with {fields} (tbltemplates \u2014 shared with the website).",
                    "Templates"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/templates\/{id}": {
            "patch": {
                "operationId": "templates.update",
                "summary": "Edit a template",
                "tags": [
                    "Templates\n\nSaved messages with {fields} (tbltemplates \u2014 shared with the website).",
                    "Templates"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            },
            "delete": {
                "operationId": "templates.destroy",
                "summary": "Delete a template (hidden, like on the website)",
                "tags": [
                    "Templates\n\nSaved messages with {fields} (tbltemplates \u2014 shared with the website).",
                    "Templates"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        },
        "\/v1\/templates\/{id}\/sample": {
            "get": {
                "operationId": "templates.sample",
                "description": "CSV with the columns Template SMS needs: mobile first, then one per\n{field}, and an example row.",
                "summary": "Sample recipients file",
                "tags": [
                    "Templates\n\nSaved messages with {fields} (tbltemplates \u2014 shared with the website).",
                    "Templates"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "text\/csv; charset=UTF-8": {
                                "schema": {
                                    "type": "string",
                                    "format": "binary"
                                }
                            }
                        },
                        "headers": {
                            "Transfer-Encoding": {
                                "required": true,
                                "schema": {
                                    "type": "string",
                                    "enum": [
                                        "chunked"
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#\/components\/responses\/AuthenticationException"
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "http": {
                "type": "http",
                "scheme": "bearer"
            }
        },
        "schemas": {
            "ChangePasswordRequest": {
                "type": "object",
                "description": "Website rules (changepassword.php): 6\u201319 characters.",
                "properties": {
                    "current_password": {
                        "type": "string"
                    },
                    "password": {
                        "type": "string",
                        "minLength": 6,
                        "maxLength": 19
                    },
                    "password_confirmation": {
                        "type": "string",
                        "minLength": 6,
                        "maxLength": 19
                    }
                },
                "required": [
                    "current_password",
                    "password",
                    "password_confirmation"
                ],
                "title": "ChangePasswordRequest"
            },
            "MobileRequest": {
                "type": "object",
                "properties": {
                    "mobile": {
                        "type": "string",
                        "description": "8-digit Kuwaiti mobile. @example 94404010"
                    }
                },
                "required": [
                    "mobile"
                ],
                "title": "MobileRequest"
            },
            "RegisterRequest": {
                "type": "object",
                "description": "Same rules as the website's register.php.",
                "properties": {
                    "fullname": {
                        "type": "string",
                        "examples": [
                            "Ahmad Al-Sabah"
                        ],
                        "minLength": 2,
                        "maxLength": 255
                    },
                    "mobile": {
                        "type": "string",
                        "examples": [
                            "94404010"
                        ]
                    },
                    "email": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "email",
                        "maxLength": 255
                    },
                    "company": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 255
                    },
                    "password": {
                        "type": "string",
                        "description": "Website password, 6\u201319 characters. The app itself logs in with SMS codes.",
                        "minLength": 6,
                        "maxLength": 19
                    },
                    "agree": {
                        "description": "Must be true.",
                        "enum": [
                            "yes",
                            "on",
                            "1",
                            1,
                            "true",
                            true
                        ]
                    }
                },
                "required": [
                    "fullname",
                    "mobile",
                    "password"
                ],
                "title": "RegisterRequest"
            },
            "SendMessageRequest": {
                "type": "object",
                "properties": {
                    "message": {
                        "type": "string",
                        "description": "Message text. {name} and {number} are filled from your contacts. @example Hi {name}, our sale starts Thursday!",
                        "maxLength": 2000
                    },
                    "numbers": {
                        "type": "array",
                        "description": "Mobile numbers typed by the user. @example [\"94404010\", \"66123456\"]",
                        "items": {
                            "type": "string",
                            "maxLength": 20
                        },
                        "maxItems": 50000
                    },
                    "group_ids": {
                        "type": "array",
                        "description": "Group ids whose numbers get the message.",
                        "items": {
                            "type": "integer",
                            "minimum": 1
                        },
                        "maxItems": 200
                    },
                    "sender": {
                        "type": "string",
                        "description": "One of your sender IDs (GET \/sender-ids).",
                        "maxLength": 50
                    },
                    "schedule_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time",
                        "description": "Send later: ISO-8601 time at least 2 minutes ahead, up to a year. Leave out to send now. @example 2026-10-15T09:30:00+03:00"
                    }
                },
                "required": [
                    "message",
                    "sender"
                ],
                "title": "SendMessageRequest"
            },
            "UpdateProfileRequest": {
                "type": "object",
                "properties": {
                    "fullname": {
                        "type": "string",
                        "minLength": 2,
                        "maxLength": 255
                    },
                    "email": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "email",
                        "maxLength": 255
                    },
                    "company": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 255
                    }
                },
                "title": "UpdateProfileRequest"
            },
            "VerifyCodeRequest": {
                "type": "object",
                "properties": {
                    "mobile": {
                        "type": "string",
                        "examples": [
                            "94404010"
                        ]
                    },
                    "code": {
                        "type": "string",
                        "description": "The code from the SMS. @example 4821",
                        "pattern": "^\\d{4,6}$"
                    },
                    "device_name": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Shown in the list of logged-in devices. @example Pixel 8",
                        "maxLength": 100
                    }
                },
                "required": [
                    "mobile",
                    "code"
                ],
                "title": "VerifyCodeRequest"
            }
        },
        "responses": {
            "ValidationException": {
                "description": "Validation error",
                "content": {
                    "application\/json": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "message": {
                                    "type": "string",
                                    "description": "Errors overview."
                                },
                                "errors": {
                                    "type": "object",
                                    "description": "A detailed description of each field that failed validation.",
                                    "additionalProperties": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        }
                                    }
                                }
                            },
                            "required": [
                                "message",
                                "errors"
                            ]
                        }
                    }
                }
            },
            "AuthenticationException": {
                "description": "Unauthenticated",
                "content": {
                    "application\/json": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "message": {
                                    "type": "string",
                                    "description": "Error overview."
                                }
                            },
                            "required": [
                                "message"
                            ]
                        }
                    }
                }
            }
        }
    }
}