{
  "openapi": "3.1.0",
  "info": {
    "title": "Esemes Gateway API",
    "version": "1",
    "description": "Send SMS and one-time codes from your own Android phone + SIM. Mauritian mobile numbers only. Live keys smk_..., test keys smt_... (nothing sent, results simulated). Errors: {\"error\":{\"code\",\"message\"}}. Human docs: /docs on the console; agents: /llms-full.txt."
  },
  "servers": [{ "url": "https://sms.bizmakers.app" }],
  "security": [{ "bearer": [] }],
  "paths": {
    "/v1/messages": {
      "post": {
        "operationId": "sendMessage",
        "summary": "Send an SMS",
        "parameters": [{ "name": "Idempotency-Key", "in": "header", "schema": { "type": "string", "maxLength": 128 } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendRequest" } } } },
        "responses": {
          "202": { "description": "Queued", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Message" } } } },
          "200": { "description": "Idempotent replay (header Idempotent-Replay: true)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Message" } } } },
          "4XX": { "$ref": "#/components/responses/Error" }
        }
      },
      "get": {
        "operationId": "listMessages",
        "summary": "List messages, newest first (50 per page)",
        "parameters": [
          { "name": "state", "in": "query", "schema": { "$ref": "#/components/schemas/State" } },
          { "name": "kind", "in": "query", "schema": { "type": "string" } },
          { "name": "to", "in": "query", "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "maximum": 200 } },
          { "name": "before", "in": "query", "description": "next_before from the previous page", "schema": { "type": "string", "format": "date-time" } }
        ],
        "responses": {
          "200": { "description": "Page", "content": { "application/json": { "schema": { "type": "object", "properties": {
            "data": { "type": "array", "items": { "$ref": "#/components/schemas/Message" } },
            "next_before": { "type": "string", "format": "date-time" } } } } } },
          "4XX": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1/messages/{id}": {
      "get": {
        "operationId": "getMessage",
        "summary": "A message with its event history",
        "parameters": [{ "$ref": "#/components/parameters/Id" }],
        "responses": { "200": { "description": "Message", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Message" } } } }, "4XX": { "$ref": "#/components/responses/Error" } }
      }
    },
    "/v1/messages/{id}/cancel": {
      "post": {
        "operationId": "cancelMessage",
        "summary": "Cancel a message still queued or scheduled",
        "parameters": [{ "$ref": "#/components/parameters/Id" }],
        "responses": { "200": { "description": "Canceled", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Message" } } } }, "4XX": { "$ref": "#/components/responses/Error" } }
      }
    },
    "/v1/usage": {
      "get": {
        "operationId": "usage",
        "summary": "Messages sent and quotas",
        "responses": { "200": { "description": "Usage", "content": { "application/json": { "schema": { "type": "object", "properties": {
          "last_24h": { "type": "integer" }, "last_30d": { "type": "integer" },
          "limit_per_minute": { "type": ["integer", "null"] }, "limit_per_day": { "type": ["integer", "null"] }, "limit_per_month": { "type": ["integer", "null"] } } } } } } }
      }
    },
    "/v1/otp": {
      "post": {
        "operationId": "sendOtp",
        "summary": "Generate and send a one-time code",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["to"], "properties": {
          "to": { "type": "string", "description": "Mauritian mobile" },
          "purpose": { "type": "string", "default": "login" },
          "length": { "type": "integer", "minimum": 4, "maximum": 10, "default": 6 },
          "ttl_seconds": { "type": "integer", "minimum": 60, "maximum": 1800, "default": 300 },
          "template": { "type": "string" }, "locale": { "type": "string" }, "params": { "type": "object" },
          "idempotency_key": { "type": "string" } } } } } },
        "responses": {
          "202": { "description": "Sent", "content": { "application/json": { "schema": { "type": "object", "properties": {
            "otp_id": { "type": "string", "format": "uuid" }, "message_id": { "type": "string", "format": "uuid" }, "to": { "type": "string" },
            "expires_at": { "type": "string", "format": "date-time" },
            "test_code": { "type": "string", "description": "Only with a test key" } } } } } },
          "4XX": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1/otp/verify": {
      "post": {
        "operationId": "verifyOtp",
        "summary": "Check a code (by otp_id, or by to + purpose)",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["code"], "properties": {
          "otp_id": { "type": "string", "format": "uuid" }, "to": { "type": "string" }, "purpose": { "type": "string" }, "code": { "type": "string" } } } } } },
        "responses": { "200": { "description": "Result", "content": { "application/json": { "schema": { "type": "object", "properties": {
          "valid": { "type": "boolean" },
          "reason": { "type": "string", "enum": ["incorrect", "expired_or_used", "too_many_attempts", "not_found"] },
          "attempts_left": { "type": "integer" } } } } } }, "4XX": { "$ref": "#/components/responses/Error" } }
      }
    },
    "/v1/templates": {
      "get": { "operationId": "listTemplates", "summary": "List templates", "responses": { "200": { "description": "Templates" } } }
    },
    "/v1/templates/{key}": {
      "put": {
        "operationId": "putTemplate", "summary": "Create or replace a template ({{.name}} variables)",
        "parameters": [{ "name": "key", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["body"], "properties": {
          "locale": { "type": "string", "default": "en" }, "body": { "type": "string" } } } } } },
        "responses": { "200": { "description": "Saved" }, "4XX": { "$ref": "#/components/responses/Error" } }
      },
      "delete": {
        "operationId": "deleteTemplate", "summary": "Delete a template",
        "parameters": [{ "name": "key", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "locale", "in": "query", "schema": { "type": "string" } }],
        "responses": { "204": { "description": "Deleted" } }
      }
    },
    "/v1/webhooks": {
      "get": { "operationId": "listWebhooks", "summary": "List webhooks", "responses": { "200": { "description": "Webhooks" } } },
      "post": {
        "operationId": "createWebhook", "summary": "Add a webhook (returns the signing secret once)",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["url"], "properties": {
          "url": { "type": "string", "description": "public https" },
          "events": { "type": "array", "items": { "type": "string", "enum": ["message.queued", "message.dispatched", "message.sent", "message.delivered", "message.failed", "message.expired", "message.canceled", "message.retried", "message.received"] } } } } } } },
        "responses": { "201": { "description": "Created, with secret" }, "4XX": { "$ref": "#/components/responses/Error" } }
      }
    },
    "/v1/webhooks/{id}": {
      "delete": { "operationId": "deleteWebhook", "summary": "Delete a webhook", "parameters": [{ "$ref": "#/components/parameters/Id" }], "responses": { "204": { "description": "Deleted" } } }
    }
  },
  "components": {
    "securitySchemes": { "bearer": { "type": "http", "scheme": "bearer", "description": "Project key: smk_... (live) or smt_... (test)" } },
    "parameters": { "Id": { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } },
    "responses": {
      "Error": { "description": "Error", "content": { "application/json": { "schema": { "type": "object", "properties": {
        "error": { "type": "object", "properties": { "code": { "type": "string", "examples": ["country_not_allowed", "recipient_suppressed", "quota_exceeded", "otp_cooldown", "idempotency_conflict", "unauthorized"] }, "message": { "type": "string" } } } } } } } }
    },
    "schemas": {
      "State": { "type": "string", "enum": ["scheduled", "queued", "dispatched", "sent", "delivered", "failed", "expired", "canceled", "received"] },
      "SendRequest": {
        "type": "object", "required": ["to"],
        "properties": {
          "to": { "type": "string", "description": "Mauritian mobile, e.g. 5123 4567 or +23051234567" },
          "body": { "type": "string", "maxLength": 1600 },
          "template": { "type": "string" }, "locale": { "type": "string" }, "params": { "type": "object" },
          "kind": { "type": "string", "enum": ["transactional", "notification", "bulk", "otp"] },
          "priority": { "type": "integer", "minimum": 0, "maximum": 9 },
          "ttl_seconds": { "type": "integer", "minimum": 30, "maximum": 604800 },
          "scheduled_at": { "type": "string", "format": "date-time" },
          "idempotency_key": { "type": "string", "maxLength": 128 },
          "sim_slot": { "type": "integer", "minimum": 0, "maximum": 3, "description": "SIM slot (0 = SIM 1). With several phones, combine with device_id." },
          "device_id": { "type": "string", "format": "uuid", "description": "Send from this phone only (id from the console's Phones page). Default: any online phone." },
          "metadata": { "type": "object" }
        }
      },
      "Message": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" }, "project_id": { "type": "string", "format": "uuid" },
          "direction": { "type": "string", "enum": ["outbound", "inbound"] }, "test": { "type": "boolean" },
          "to": { "type": "string" }, "body": { "type": "string" }, "kind": { "type": "string" }, "priority": { "type": "integer" },
          "state": { "$ref": "#/components/schemas/State" }, "attempts": { "type": "integer" },
          "segments": { "type": "integer" }, "encoding": { "type": "string" },
          "error_code": { "type": "string" }, "error_detail": { "type": "string" },
          "expires_at": { "type": "string", "format": "date-time" }, "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }, "metadata": { "type": "object" },
          "events": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string" }, "data": { "type": "object" }, "at": { "type": "string", "format": "date-time" } } } }
        }
      }
    }
  }
}
