{
  "openapi": "3.0.3",
  "info": {
    "title": "BuySMS SMS API",
    "version": "1.0.0",
    "description": "Send single, bulk and personalised SMS to Bangladeshi mobile numbers, check delivery status and balance. Get an API key from the panel at https://app.buysms.bd (Developer API). Human-readable docs: https://buysms.bd/en/api",
    "contact": { "url": "https://buysms.bd/en#contact" }
  },
  "externalDocs": { "description": "Full documentation", "url": "https://buysms.bd/en/api" },
  "servers": [ { "url": "https://app.buysms.bd/api/v1" } ],
  "security": [ { "ApiKeyHeader": [] }, { "ApiKeyQuery": [] } ],
  "paths": {
    "/sms/send": {
      "post": {
        "operationId": "sendSms",
        "summary": "Send the same SMS to one or many numbers",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/SendRequest" } },
            "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/SendRequest" } }
          }
        },
        "responses": {
          "200": { "description": "Queued", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendResult" } } } },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" },
          "402": { "$ref": "#/components/responses/Error" }
        }
      },
      "get": {
        "operationId": "sendSmsGet",
        "summary": "Send SMS with a GET request (simple integrations)",
        "parameters": [
          { "name": "to", "in": "query", "required": true, "schema": { "type": "string" }, "description": "Mobile number(s), comma separated", "example": "01711000000" },
          { "name": "message", "in": "query", "required": true, "schema": { "type": "string", "maxLength": 1000 } },
          { "name": "sender_id", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Masking sender ID; empty = non-masking" }
        ],
        "responses": {
          "200": { "description": "Queued", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendResult" } } } },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" },
          "402": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/sms/bulk": {
      "post": {
        "operationId": "sendBulkSms",
        "summary": "Send a different message to each number in one request",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkRequest" } } }
        },
        "responses": {
          "200": { "description": "Queued", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendResult" } } } },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" },
          "402": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/sms/status/{id}": {
      "get": {
        "operationId": "getSmsStatus",
        "summary": "Delivery status of one message",
        "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "messages[].id from the send response" } ],
        "responses": {
          "200": { "description": "Status", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Status" } } } },
          "401": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/balance": {
      "get": {
        "operationId": "getBalance",
        "summary": "Balance, rates and masking sender IDs",
        "responses": {
          "200": { "description": "Balance", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Balance" } } } },
          "401": { "$ref": "#/components/responses/Error" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": { "type": "apiKey", "in": "header", "name": "X-API-KEY" },
      "ApiKeyQuery": { "type": "apiKey", "in": "query", "name": "api_key" }
    },
    "responses": {
      "Error": { "description": "Error (nothing is charged)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
    },
    "schemas": {
      "SendRequest": {
        "type": "object",
        "required": [ "to", "message" ],
        "properties": {
          "to": { "type": "string", "description": "Bangladeshi mobile number(s): 01XXXXXXXXX, 8801XXXXXXXXX or +8801XXXXXXXXX. Several: comma separated (max 50000).", "example": "01711000000,01811000000" },
          "message": { "type": "string", "maxLength": 1000, "description": "English or Bangla text. 160/153 chars per part (GSM), 70/67 (Unicode).", "example": "Your OTP is 4821" },
          "sender_id": { "type": "string", "description": "Masking sender ID assigned to your account. Empty or omitted = non-masking.", "example": "" },
          "api_key": { "type": "string", "description": "Alternative to the X-API-KEY header" }
        }
      },
      "BulkRequest": {
        "type": "object",
        "required": [ "messages" ],
        "properties": {
          "sender_id": { "type": "string", "description": "Masking sender ID for all messages; empty = non-masking" },
          "api_key": { "type": "string", "description": "Alternative to the X-API-KEY header" },
          "messages": {
            "type": "array", "maxItems": 50000,
            "items": {
              "type": "object", "required": [ "to", "message" ],
              "properties": { "to": { "type": "string", "example": "01711000000" }, "message": { "type": "string", "maxLength": 1000, "example": "Dear Rahim, your bill is 1,200 Tk." } }
            }
          }
        }
      },
      "SendResult": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean", "example": true },
          "batch_id": { "type": "string", "format": "uuid" },
          "queued": { "type": "integer", "description": "Number of SMS queued" },
          "parts": { "type": "integer", "description": "Total SMS parts charged" },
          "cost": { "type": "number", "description": "Total cost in BDT" },
          "balance": { "type": "number", "description": "Balance after this request, BDT" },
          "invalid_numbers": { "type": "array", "items": { "type": "string" }, "description": "Skipped numbers" },
          "messages": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "to": { "type": "string", "example": "8801711000000" } } } }
        }
      },
      "Status": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean" },
          "id": { "type": "string", "format": "uuid" },
          "to": { "type": "string" },
          "status": { "type": "string", "enum": [ "queued", "sending", "sent", "failed" ] },
          "parts": { "type": "integer" },
          "cost": { "type": "number" },
          "error": { "type": "string", "nullable": true },
          "queued_at": { "type": "string", "description": "Bangladesh time, e.g. 28 Sep 2026, 03:15 PM" },
          "finished_at": { "type": "string", "nullable": true }
        }
      },
      "Balance": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean" },
          "balance": { "type": "number" },
          "currency": { "type": "string", "example": "BDT" },
          "rate_non_masking": { "type": "number" },
          "rate_masking": { "type": "number" },
          "masking_sender_ids": { "type": "array", "items": { "type": "string" } }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean", "example": false },
          "code": { "type": "string", "enum": [ "invalid_api_key", "insufficient_balance", "missing_to", "missing_message", "missing_messages", "invalid_json", "rejected", "not_found" ] },
          "error": { "type": "string" },
          "invalid_numbers": { "type": "array", "items": { "type": "string" }, "nullable": true }
        }
      }
    }
  }
}