{
    "openapi": "3.1.0",
    "info": {
        "title": "Ping Africa API Documentation",
        "version": "1.7.7",
        "description": "# Ping Africa Unified Communication API\n\nSend SMS, WhatsApp messages, manage USSD sessions, and handle credits \u2014 all from one API.\n\n## Prerequisites\n\nBefore using the API, ensure you have:\n1. **Account** \u2014 Register at [bulk.ping.africa](https://bulk.ping.africa)\n2. **API Token** \u2014 Generate from your dashboard (see below)\n3. **Sender ID** \u2014 New accounts get `PING-AFRICA` by default\n4. **Credits** \u2014 Purchase credits to send messages\n\n---\n\n## Step 1: Get Your API Token\n\n1. Login to [bulk.ping.africa](https://bulk.ping.africa)\n2. Go to **Account Settings** \u2192 **API Tokens**\n3. Click **Create Token**\n4. Name your token (e.g., \"Production API\")\n5. Copy the token immediately (shown only once)\n\n---\n\n## Step 2: Use Your Token\n\nAll authenticated requests require the `Authorization` header:\n\n```http\nAuthorization: Bearer YOUR_TOKEN_HERE\n```\n\n---\n\n## Step 3: Send Your First SMS\n\n```bash\ncurl -X POST https://bulk.ping.africa/api/sms/send \\\n  -H \"Authorization: Bearer YOUR_TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"recipient\": \"+254712345678\",\n    \"message\": \"Hello from Ping Africa!\",\n    \"sender_id\": \"PING-AFRICA\"\n  }'\n```\n\n**Response:**\n```json\n{\n  \"success\": true,\n  \"message\": {\n    \"status\": \"sent\",\n    \"recipient\": \"+254712345678\",\n    \"parts\": 1\n  },\n  \"credits_charged\": \"0.20\",\n  \"new_balance\": 106.6\n}\n```\n\n### Send Bulk SMS\n\nSend the same message to multiple recipients in one call:\n\n```bash\ncurl -X POST https://bulk.ping.africa/api/sms/send-bulk \\\n  -H \"Authorization: Bearer YOUR_TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"recipients\": [\"+254712345678\", \"+254723456789\"],\n    \"message\": \"Bulk message to all!\",\n    \"sender_id\": \"PING-AFRICA\"\n  }'\n```\n\n---\n\n## Sender IDs\n\n### What is a Sender ID?\nThe name/number that appears as the sender when recipients receive your SMS.\n\n### Default Sender ID\nNew organizations are automatically granted access to `PING-AFRICA`.\n\n### Using Sender IDs\n- **Specify in request:** Include `sender_id` parameter\n- **Auto-select:** If omitted, your default authorized sender ID is used\n- **No sender ID?** Request returns error with available options\n\n### Getting Your Own Sender ID\nApply via Dashboard \u2192 Shortcodes \u2192 Apply for Sender ID\n\n**Error when no sender ID available:**\n```json\n{\n  \"error\": \"No sender ID available. You must have at least one verified shortcode or authorized system sender ID.\",\n  \"available_sender_ids\": []\n}\n```\n\n---\n\n## Step 4: Send WhatsApp Messages\n\nWhatsApp messaging requires a connected WhatsApp instance. Set up your instance from the Dashboard under **WhatsApp \u2192 Instances**.\n\n### List Your Instances\n\nFirst, retrieve your connected WhatsApp instances to get the `instanceName` needed for sending messages:\n\n```bash\ncurl -X GET https://bulk.ping.africa/api/whatsapp/instances \\\n  -H \"Authorization: Bearer $TOKEN\"\n```\n\n**Response:**\n```json\n{\n  \"success\": true,\n  \"data\": [\n    {\n      \"name\": \"my-instance\",\n      \"connectionStatus\": \"open\",\n      \"profileName\": \"My Business\"\n    }\n  ]\n}\n```\n\nUse the `name` field as `instanceName` in your message requests below. Only instances with `connectionStatus: \"open\"` can send messages.\n\n### Send a Text Message\n```bash\ncurl -X POST https://bulk.ping.africa/api/whatsapp/messages/text \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"instanceName\": \"my-instance\",\n    \"number\": \"254712345678\",\n    \"text\": \"Hello from Ping Africa!\"\n  }'\n```\n\n**Response:**\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"key\": {\n      \"id\": \"3EB0148249BCB40099292C\"\n    },\n    \"status\": \"PENDING\",\n    \"messageType\": \"conversation\"\n  }\n}\n```\n\nThe `key.id` is the message ID you can use to track delivery.\n\n### Send a Document (PDF, Word, Excel, etc.)\n```bash\ncurl -X POST https://bulk.ping.africa/api/whatsapp/messages/media \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"instanceName\": \"my-instance\",\n    \"number\": \"254712345678\",\n    \"mediatype\": \"document\",\n    \"media\": \"https://example.com/report.pdf\",\n    \"caption\": \"Monthly Report\",\n    \"fileName\": \"Report-Feb-2026.pdf\"\n  }'\n```\n\n### Send an Image\n```bash\ncurl -X POST https://bulk.ping.africa/api/whatsapp/messages/media \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"instanceName\": \"my-instance\",\n    \"number\": \"254712345678\",\n    \"mediatype\": \"image\",\n    \"media\": \"https://example.com/photo.jpg\",\n    \"caption\": \"Check this out!\"\n  }'\n```\n\n### Send a Video\n```bash\ncurl -X POST https://bulk.ping.africa/api/whatsapp/messages/media \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"instanceName\": \"my-instance\",\n    \"number\": \"254712345678\",\n    \"mediatype\": \"video\",\n    \"media\": \"https://example.com/promo.mp4\",\n    \"caption\": \"Watch our latest update\"\n  }'\n```\n\n### Send Audio\n```bash\ncurl -X POST https://bulk.ping.africa/api/whatsapp/messages/media \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"instanceName\": \"my-instance\",\n    \"number\": \"254712345678\",\n    \"mediatype\": \"audio\",\n    \"media\": \"https://example.com/message.mp3\"\n  }'\n```\n\n### WhatsApp Media Types\n\n| mediatype | Use for | Formats |\n|-----------|---------|---------|\n| `document` | Files, PDFs, spreadsheets | PDF, DOC, DOCX, XLS, XLSX, CSV |\n| `image` | Photos, graphics | JPG, PNG, WEBP |\n| `video` | Video clips | MP4, 3GP |\n| `audio` | Voice notes, audio files | MP3, OGG, AAC |\n\n> **Note:** The `number` field should be the phone number **without** the `+` prefix (e.g., `254712345678` not `+254712345678`). The `media` field must be a publicly accessible URL.\n\n---\n\n## Step 5: USSD Sessions\n\nBuild interactive USSD menus for your users. USSD sessions follow a request-response flow: initiate a session, send user inputs, and complete or cancel when done.\n\n### Initiate a Session\n```bash\ncurl -X POST https://bulk.ping.africa/api/ussd/initiate \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"session_id\": \"unique-session-123\",\n    \"phone_number\": \"+254712345678\",\n    \"service_code\": \"*384*100#\"\n  }'\n```\n\n**Response:**\n```json\n{\n  \"success\": true,\n  \"session\": {\n    \"id\": 1,\n    \"session_id\": \"unique-session-123\",\n    \"status\": \"active\"\n  },\n  \"response\": \"CON Welcome to our service\\n1. Check Balance\\n2. Buy Airtime\\n3. Exit\"\n}\n```\n\n### Send User Input\n```bash\ncurl -X POST https://bulk.ping.africa/api/ussd/interact/unique-session-123 \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"user_input\": \"1\"\n  }'\n```\n\n**Response:**\n```json\n{\n  \"success\": true,\n  \"response\": \"END Your balance is KES 1,500.00\",\n  \"is_end\": true\n}\n```\n\n### Complete a Session (charges credits)\n```bash\ncurl -X POST https://bulk.ping.africa/api/ussd/complete/unique-session-123 \\\n  -H \"Authorization: Bearer $TOKEN\"\n```\n\n### Cancel a Session\n```bash\ncurl -X POST https://bulk.ping.africa/api/ussd/cancel/unique-session-123 \\\n  -H \"Authorization: Bearer $TOKEN\"\n```\n\n### Get Session Details\n```bash\ncurl -X GET https://bulk.ping.africa/api/ussd/session/unique-session-123 \\\n  -H \"Authorization: Bearer $TOKEN\"\n```\n\n> **USSD Response Prefixes:** Responses prefixed with `CON` mean the session continues (show menu, wait for input). Responses prefixed with `END` mean the session is complete (show message, close).\n\n---\n\n## Step 6: Credits & Billing\n\nCheck your balance before sending messages and track your spending.\n\n### Check Balance\n```bash\ncurl -X GET https://bulk.ping.africa/api/credits/balance \\\n  -H \"Authorization: Bearer $TOKEN\"\n```\n\n**Response:**\n```json\n{\n  \"balance\": 106.6\n}\n```\n\n### Estimate Cost Before Sending\n```bash\ncurl -X POST https://bulk.ping.africa/api/credits/estimate \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"service_type\": \"sms_local\",\n    \"quantity\": 500\n  }'\n```\n\n**Response:**\n```json\n{\n  \"service_type\": \"sms_local\",\n  \"quantity\": 500,\n  \"credits\": 100,\n  \"sufficient_credits\": true\n}\n```\n\n**Service types:** `sms_local`, `sms_international`, `whatsapp`, `ussd`\n\n### View Available Packages\n```bash\ncurl -X GET https://bulk.ping.africa/api/credits/packages\n```\n\n> **Note:** Credit packages and pricing endpoints are public \u2014 no authentication required.\n\n---\n\n## Available APIs\n\n| API | Description | Key Endpoints |\n|-----|-------------|---------------|\n| **SMS** | Send single & bulk SMS | `POST /api/sms/send`, `POST /api/sms/send-bulk` |\n| **WhatsApp** | Send text, images, docs, video, audio | `POST /api/whatsapp/messages/text`, `POST /api/whatsapp/messages/media` |\n| **USSD** | Interactive USSD menus | `POST /api/ussd/initiate`, `POST /api/ussd/interact/{sessionId}` |\n| **Credits** | Balance, pricing, cost estimates | `GET /api/credits/balance`, `GET /api/credits/packages`, `POST /api/credits/estimate` |\n\n---\n\n## Error Codes\n\n| Code | Meaning |\n|------|---------|\n| 200/201 | Success |\n| 400 | Bad request (e.g., no sender ID) |\n| 401 | Unauthorized (invalid or missing token) |\n| 402 | Insufficient credits |\n| 404 | Resource not found (e.g., session ID) |\n| 422 | Validation failed (check `messages` field for details) |\n| 429 | Rate limit exceeded (wait and retry) |\n\n---\n\n## Rate Limits\n\n| Endpoint | Limit |\n|----------|-------|\n| SMS & WhatsApp | 60 requests/minute |\n| Credits & USSD | 100 requests/minute |\n\n---\n\n## Quick Start (Complete Example)\n\n```bash\n# Set your token\nTOKEN=\"your-api-token-here\"\n\n# 1. Check credit balance\ncurl -s -X GET https://bulk.ping.africa/api/credits/balance \\\n  -H \"Authorization: Bearer $TOKEN\"\n\n# 2. Send a single SMS\ncurl -s -X POST https://bulk.ping.africa/api/sms/send \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"recipient\": \"+254712345678\",\n    \"message\": \"Hello from Ping Africa!\",\n    \"sender_id\": \"PING-AFRICA\"\n  }'\n\n# 3. Send bulk SMS\ncurl -s -X POST https://bulk.ping.africa/api/sms/send-bulk \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"recipients\": [\"+254712345678\", \"+254723456789\"],\n    \"message\": \"Bulk message to all!\",\n    \"sender_id\": \"PING-AFRICA\"\n  }'\n\n# 4. Send a WhatsApp text message\ncurl -s -X POST https://bulk.ping.africa/api/whatsapp/messages/text \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"instanceName\": \"my-instance\",\n    \"number\": \"254712345678\",\n    \"text\": \"Hello via WhatsApp!\"\n  }'\n\n# 5. Send a PDF via WhatsApp\ncurl -s -X POST https://bulk.ping.africa/api/whatsapp/messages/media \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"instanceName\": \"my-instance\",\n    \"number\": \"254712345678\",\n    \"mediatype\": \"document\",\n    \"media\": \"https://example.com/invoice.pdf\",\n    \"caption\": \"Your invoice\",\n    \"fileName\": \"Invoice-001.pdf\"\n  }'\n\n# 6. Start a USSD session\ncurl -s -X POST https://bulk.ping.africa/api/ussd/initiate \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"session_id\": \"session-001\",\n    \"phone_number\": \"+254712345678\",\n    \"service_code\": \"*384*100#\"\n  }'\n```\n\n---\n\n## Support\n\n- Email: support@ping.africa\n- Dashboard: [bulk.ping.africa](https://bulk.ping.africa)"
    },
    "servers": [
        {
            "url": "https://bulk.ping.africa/api"
        }
    ],
    "security": [
        {
            "http": []
        }
    ],
    "paths": {
        "/credits/packages": {
            "get": {
                "operationId": "credit.packages",
                "description": "Returns all available credit packages for purchase.\n\n**Access:** Public (no authentication required)",
                "summary": "Get Available Credit Packages",
                "tags": [
                    "Credits"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "integer",
                                    "enum": [
                                        200
                                    ]
                                }
                            }
                        }
                    }
                },
                "security": []
            }
        },
        "/credits/pricing": {
            "get": {
                "operationId": "credit.pricing",
                "description": "Returns pricing information for all services (SMS, WhatsApp, USSD, etc.).\nUse this to calculate costs before making API calls.\n\n**Access:** Public (no authentication required)",
                "summary": "Get Credit Pricing",
                "tags": [
                    "Credits"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "integer",
                                    "enum": [
                                        200
                                    ]
                                }
                            }
                        }
                    }
                },
                "security": []
            }
        },
        "/credits/balance": {
            "get": {
                "operationId": "credit.balance",
                "description": "Returns the current credit balance for your organization.\n\n**Access:** Organization users and superadmins\n**Scope:** Your organization only",
                "summary": "Get Organization Credit Balance",
                "tags": [
                    "Credits"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "integer",
                                    "enum": [
                                        200
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            }
        },
        "/credits/estimate": {
            "post": {
                "operationId": "credit.estimate",
                "description": "Calculates how many credits a specific service operation will cost.\n\n**Access:** Organization users and superadmins\n**Scope:** Your organization pricing",
                "summary": "Estimate Credit Cost",
                "tags": [
                    "Credits"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "service_type": {
                                        "type": "string"
                                    },
                                    "quantity": {
                                        "type": "integer",
                                        "minimum": 1
                                    }
                                },
                                "required": [
                                    "service_type"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "integer",
                                    "enum": [
                                        200
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            }
        },
        "/sms/send": {
            "post": {
                "operationId": "smsMessage.send",
                "description": "Sends a single SMS message to one recipient. The message is sent using your organization's active SMS provider\nand credits are automatically deducted from your balance.\n\n**Access:** Organization users and superadmins\n**Scope:** Your organization only",
                "summary": "Send Single SMS Message",
                "tags": [
                    "SMS"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "recipient": {
                                        "type": "string"
                                    },
                                    "message": {
                                        "type": "string",
                                        "maxLength": 1600
                                    },
                                    "sender_id": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "maxLength": 11
                                    }
                                },
                                "required": [
                                    "recipient",
                                    "message"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "integer",
                                    "enum": [
                                        201
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            }
        },
        "/sms/send-bulk": {
            "post": {
                "operationId": "smsMessage.sendBulk",
                "description": "Sends SMS to multiple recipients in a single batch. Maximum 1000 recipients per request.\nCredits are only charged for successfully sent messages.\n\n**Access:** Organization users and superadmins\n**Scope:** Your organization only",
                "summary": "Send Bulk SMS Messages",
                "tags": [
                    "SMS"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "message": {
                                        "type": "string",
                                        "maxLength": 1600
                                    },
                                    "sender_id": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "maxLength": 11
                                    },
                                    "recipients": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        },
                                        "minItems": 1,
                                        "maxItems": 1000
                                    }
                                },
                                "required": [
                                    "message",
                                    "recipients"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "integer",
                                    "enum": [
                                        201
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            }
        },
        "/ussd/initiate": {
            "post": {
                "operationId": "ussdSession.initiate",
                "summary": "Initiate USSD session",
                "tags": [
                    "USSD"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "session_id": {
                                        "type": "string"
                                    },
                                    "phone_number": {
                                        "type": "string"
                                    },
                                    "service_code": {
                                        "type": "string"
                                    },
                                    "shortcode_id": {
                                        "type": [
                                            "integer",
                                            "null"
                                        ]
                                    },
                                    "language": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "enum": [
                                            "en",
                                            "sw"
                                        ]
                                    }
                                },
                                "required": [
                                    "session_id",
                                    "phone_number",
                                    "service_code"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "500": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "error": {
                                            "type": "string"
                                        }
                                    },
                                    "required": [
                                        "error"
                                    ]
                                }
                            }
                        }
                    },
                    "201": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "session": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "string"
                                                },
                                                "session_id": {
                                                    "type": "string"
                                                },
                                                "status": {
                                                    "type": "string"
                                                }
                                            },
                                            "required": [
                                                "id",
                                                "session_id",
                                                "status"
                                            ]
                                        },
                                        "response": {
                                            "type": "string",
                                            "enum": [
                                                "CON Welcome to our service\n1. Continue"
                                            ]
                                        }
                                    },
                                    "required": [
                                        "success",
                                        "session",
                                        "response"
                                    ]
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "error": {
                                            "type": "string",
                                            "enum": [
                                                "Validation failed"
                                            ]
                                        },
                                        "messages": {
                                            "type": "string"
                                        }
                                    },
                                    "required": [
                                        "error",
                                        "messages"
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            }
        },
        "/ussd/interact/{sessionId}": {
            "post": {
                "operationId": "ussdSession.interact",
                "summary": "Handle USSD session interaction",
                "tags": [
                    "USSD"
                ],
                "parameters": [
                    {
                        "name": "sessionId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "user_input": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "user_input"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "type": "object",
                                            "properties": {
                                                "success": {
                                                    "type": "boolean"
                                                },
                                                "response": {
                                                    "type": "string"
                                                },
                                                "is_end": {
                                                    "type": "string"
                                                }
                                            },
                                            "required": [
                                                "success",
                                                "response",
                                                "is_end"
                                            ]
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "success": {
                                                    "type": "boolean"
                                                },
                                                "response": {
                                                    "type": "string",
                                                    "enum": [
                                                        "END Session timed out. Please try again."
                                                    ]
                                                }
                                            },
                                            "required": [
                                                "success",
                                                "response"
                                            ]
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "error": {
                                            "type": "string",
                                            "enum": [
                                                "Session is not active"
                                            ]
                                        }
                                    },
                                    "required": [
                                        "error"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "error": {
                                            "type": "string",
                                            "enum": [
                                                "Session not found"
                                            ]
                                        }
                                    },
                                    "required": [
                                        "error"
                                    ]
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "error": {
                                            "type": "string",
                                            "enum": [
                                                "Validation failed"
                                            ]
                                        },
                                        "messages": {
                                            "type": "string"
                                        }
                                    },
                                    "required": [
                                        "error",
                                        "messages"
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            }
        },
        "/ussd/complete/{sessionId}": {
            "post": {
                "operationId": "ussdSession.complete",
                "summary": "Complete USSD session and charge credits",
                "tags": [
                    "USSD"
                ],
                "parameters": [
                    {
                        "name": "sessionId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Don't fail the session, just log",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "type": "object",
                                            "properties": {
                                                "warning": {
                                                    "type": "string",
                                                    "enum": [
                                                        "Credit tracking failed"
                                                    ]
                                                },
                                                "session": {
                                                    "type": "object",
                                                    "properties": {
                                                        "id": {
                                                            "type": "string"
                                                        },
                                                        "status": {
                                                            "type": "string"
                                                        }
                                                    },
                                                    "required": [
                                                        "id",
                                                        "status"
                                                    ]
                                                }
                                            },
                                            "required": [
                                                "warning",
                                                "session"
                                            ]
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "success": {
                                                    "type": "boolean"
                                                },
                                                "session": {
                                                    "type": "object",
                                                    "properties": {
                                                        "id": {
                                                            "type": "string"
                                                        },
                                                        "session_id": {
                                                            "type": "string"
                                                        },
                                                        "status": {
                                                            "type": "string"
                                                        },
                                                        "duration": {
                                                            "type": "string"
                                                        }
                                                    },
                                                    "required": [
                                                        "id",
                                                        "session_id",
                                                        "status",
                                                        "duration"
                                                    ]
                                                },
                                                "credits_charged": {
                                                    "type": "string"
                                                },
                                                "new_balance": {
                                                    "type": "number"
                                                },
                                                "transaction_reference": {
                                                    "type": "string"
                                                }
                                            },
                                            "required": [
                                                "success",
                                                "session",
                                                "credits_charged",
                                                "new_balance",
                                                "transaction_reference"
                                            ]
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "warning": {
                                                    "type": "string",
                                                    "enum": [
                                                        "Session completed but organization has insufficient credits"
                                                    ]
                                                },
                                                "session": {
                                                    "type": "object",
                                                    "properties": {
                                                        "id": {
                                                            "type": "string"
                                                        },
                                                        "status": {
                                                            "type": "string"
                                                        }
                                                    },
                                                    "required": [
                                                        "id",
                                                        "status"
                                                    ]
                                                },
                                                "balance": {
                                                    "type": "number"
                                                },
                                                "required": {
                                                    "type": "number"
                                                }
                                            },
                                            "required": [
                                                "warning",
                                                "session",
                                                "balance",
                                                "required"
                                            ]
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "warning": {
                                                    "type": "string",
                                                    "enum": [
                                                        "Pricing not configured"
                                                    ]
                                                },
                                                "session": {
                                                    "type": "object",
                                                    "properties": {
                                                        "id": {
                                                            "type": "string"
                                                        },
                                                        "status": {
                                                            "type": "string"
                                                        }
                                                    },
                                                    "required": [
                                                        "id",
                                                        "status"
                                                    ]
                                                }
                                            },
                                            "required": [
                                                "warning",
                                                "session"
                                            ]
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "message": {
                                                    "type": "string",
                                                    "enum": [
                                                        "Session already charged"
                                                    ]
                                                },
                                                "session": {
                                                    "type": "object",
                                                    "properties": {
                                                        "id": {
                                                            "type": "string"
                                                        },
                                                        "status": {
                                                            "type": "string"
                                                        },
                                                        "cost": {
                                                            "type": "string"
                                                        }
                                                    },
                                                    "required": [
                                                        "id",
                                                        "status",
                                                        "cost"
                                                    ]
                                                }
                                            },
                                            "required": [
                                                "message",
                                                "session"
                                            ]
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "message": {
                                                    "type": "string",
                                                    "enum": [
                                                        "Session already completed"
                                                    ]
                                                },
                                                "session": {
                                                    "type": "object",
                                                    "properties": {
                                                        "id": {
                                                            "type": "string"
                                                        },
                                                        "status": {
                                                            "type": "string"
                                                        },
                                                        "charged": {
                                                            "type": "boolean"
                                                        }
                                                    },
                                                    "required": [
                                                        "id",
                                                        "status",
                                                        "charged"
                                                    ]
                                                }
                                            },
                                            "required": [
                                                "message",
                                                "session"
                                            ]
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "error": {
                                            "type": "string",
                                            "enum": [
                                                "Session not found"
                                            ]
                                        }
                                    },
                                    "required": [
                                        "error"
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            }
        },
        "/ussd/cancel/{sessionId}": {
            "post": {
                "operationId": "ussdSession.cancel",
                "summary": "Cancel USSD session",
                "tags": [
                    "USSD"
                ],
                "parameters": [
                    {
                        "name": "sessionId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "message": {
                                            "type": "string",
                                            "enum": [
                                                "Session cancelled successfully"
                                            ]
                                        },
                                        "session": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "string"
                                                },
                                                "status": {
                                                    "type": "string"
                                                }
                                            },
                                            "required": [
                                                "id",
                                                "status"
                                            ]
                                        }
                                    },
                                    "required": [
                                        "success",
                                        "message",
                                        "session"
                                    ]
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "error": {
                                            "type": "string",
                                            "enum": [
                                                "Session is not active"
                                            ]
                                        }
                                    },
                                    "required": [
                                        "error"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "error": {
                                            "type": "string",
                                            "enum": [
                                                "Session not found"
                                            ]
                                        }
                                    },
                                    "required": [
                                        "error"
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            }
        },
        "/ussd/session/{sessionId}": {
            "get": {
                "operationId": "ussdSession.show",
                "summary": "Get session details",
                "tags": [
                    "USSD"
                ],
                "parameters": [
                    {
                        "name": "sessionId",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "session": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "string"
                                                },
                                                "session_id": {
                                                    "type": "string"
                                                },
                                                "phone_number": {
                                                    "type": "string"
                                                },
                                                "service_code": {
                                                    "type": "string"
                                                },
                                                "status": {
                                                    "type": "string"
                                                },
                                                "duration": {
                                                    "type": "string"
                                                },
                                                "total_cost": {
                                                    "type": "string"
                                                },
                                                "started_at": {
                                                    "type": "string"
                                                },
                                                "ended_at": {
                                                    "type": "string"
                                                },
                                                "is_active": {
                                                    "type": "string"
                                                }
                                            },
                                            "required": [
                                                "id",
                                                "session_id",
                                                "phone_number",
                                                "service_code",
                                                "status",
                                                "duration",
                                                "total_cost",
                                                "started_at",
                                                "ended_at",
                                                "is_active"
                                            ]
                                        }
                                    },
                                    "required": [
                                        "success",
                                        "session"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "error": {
                                            "type": "string",
                                            "enum": [
                                                "Session not found"
                                            ]
                                        }
                                    },
                                    "required": [
                                        "error"
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            }
        },
        "/webhooks/endpoints": {
            "get": {
                "operationId": "endpoints.index",
                "description": "Returns all webhook endpoints registered for your organization.",
                "summary": "List Webhook Endpoints",
                "tags": [
                    "Webhooks"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "integer",
                                    "enum": [
                                        200
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            },
            "post": {
                "operationId": "endpoints.store",
                "description": "Register a new webhook URL to receive SMS delivery notifications.\nA signing secret is auto-generated and returned in the response.\nUse it to verify webhook signatures via HMAC-SHA256.\n\n**Available events:** `sms.sent`, `sms.delivered`, `sms.failed`\n\n### Webhook Payload\n\nWhen a subscribed event fires, your URL receives a `POST` with this JSON body:\n\n```json\n{\n  \"event\": \"sms.delivered\",\n  \"timestamp\": \"2026-03-06T10:30:00+00:00\",\n  \"data\": {\n    \"message_id\": \"uuid\",\n    \"provider_message_id\": \"msg-12345\",\n    \"recipient\": \"+254712345678\",\n    \"sender_id\": \"PINGAFRICA\",\n    \"status\": \"delivered\",\n    \"delivered_at\": \"2026-03-06T10:29:55+00:00\",\n    \"failed_at\": null,\n    \"failure_reason\": null,\n    \"parts\": 1,\n    \"cost\": \"0.5000\",\n    \"batch_id\": null,\n    \"metadata\": null\n  }\n}\n```\n\n### Signature Headers\n\n| Header | Value |\n|--------|-------|\n| `X-Webhook-Signature` | `sha256=<HMAC-SHA256 of body using your secret>` |\n| `X-Webhook-Event` | Event type, e.g. `sms.delivered` |\n| `X-Webhook-Delivery-Id` | Unique delivery UUID |\n| `X-Webhook-Timestamp` | Unix timestamp |\n\n### Verification (PHP)\n\n```php\n$payload = file_get_contents('php://input');\n$expected = hash_hmac('sha256', $payload, $yourSecret);\n$actual = str_replace('sha256=', '', $request->header('X-Webhook-Signature'));\nif (!hash_equals($expected, $actual)) abort(401);\n```\n\n### Retry Policy\n\nFailed deliveries retry up to 3 times: **30s \u2192 2min \u2192 10min**.\nAfter 10 consecutive failures the endpoint is auto-disabled.",
                "summary": "Register Webhook Endpoint",
                "tags": [
                    "Webhooks"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "url": {
                                        "type": "string",
                                        "format": "uri",
                                        "maxLength": 2048
                                    },
                                    "description": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "maxLength": 255
                                    },
                                    "events": {
                                        "type": "array",
                                        "items": {
                                            "type": "string",
                                            "enum": [
                                                "sms.sent",
                                                "sms.delivered",
                                                "sms.failed"
                                            ]
                                        },
                                        "minItems": 1
                                    }
                                },
                                "required": [
                                    "url",
                                    "events"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "integer",
                                    "enum": [
                                        201
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            }
        },
        "/webhooks/endpoints/{id}": {
            "get": {
                "operationId": "endpoints.show",
                "description": "Returns details of a specific webhook endpoint, including the signing secret.",
                "summary": "Get Webhook Endpoint",
                "tags": [
                    "Webhooks"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "integer",
                                    "enum": [
                                        200
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            },
            "put": {
                "operationId": "endpoints.update",
                "description": "Update a webhook endpoint's URL, events, or active status.",
                "summary": "Update Webhook Endpoint",
                "tags": [
                    "Webhooks"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "url": {
                                        "type": "string",
                                        "format": "uri",
                                        "maxLength": 2048
                                    },
                                    "description": {
                                        "type": [
                                            "string",
                                            "null"
                                        ],
                                        "maxLength": 255
                                    },
                                    "is_active": {
                                        "type": "boolean"
                                    },
                                    "events": {
                                        "type": "array",
                                        "items": {
                                            "type": "string",
                                            "enum": [
                                                "sms.sent",
                                                "sms.delivered",
                                                "sms.failed"
                                            ]
                                        },
                                        "minItems": 1
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "integer",
                                    "enum": [
                                        200
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            },
            "delete": {
                "operationId": "endpoints.destroy",
                "description": "Permanently delete a webhook endpoint. It will stop receiving notifications immediately.",
                "summary": "Delete Webhook Endpoint",
                "tags": [
                    "Webhooks"
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "integer",
                                    "enum": [
                                        200
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            }
        },
        "/whatsapp/instances": {
            "get": {
                "operationId": "whatsApp.getInstances",
                "description": "Returns all WhatsApp instances configured for your organization.",
                "summary": "Get All WhatsApp Instances",
                "tags": [
                    "WhatsApp"
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "integer",
                                    "enum": [
                                        200
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            }
        },
        "/whatsapp/instances/{instanceName}": {
            "get": {
                "operationId": "whatsApp.getInstance",
                "summary": "Get instance details",
                "tags": [
                    "WhatsApp"
                ],
                "parameters": [
                    {
                        "name": "instanceName",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "500": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "error": {
                                            "type": "string"
                                        }
                                    },
                                    "required": [
                                        "error"
                                    ]
                                }
                            }
                        }
                    },
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "type": "string"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "success": {
                                                    "type": "boolean"
                                                },
                                                "data": {
                                                    "type": "object"
                                                }
                                            },
                                            "required": [
                                                "success",
                                                "data"
                                            ]
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "error": {
                                            "type": "string",
                                            "enum": [
                                                "WhatsApp instance not found or does not belong to your organization"
                                            ]
                                        }
                                    },
                                    "required": [
                                        "success",
                                        "error"
                                    ]
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "error": {
                                            "type": "string",
                                            "enum": [
                                                "User not associated with any organization"
                                            ]
                                        }
                                    },
                                    "required": [
                                        "error"
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            }
        },
        "/whatsapp/messages/text": {
            "post": {
                "operationId": "whatsApp.sendTextMessage",
                "description": "Send a text message to a WhatsApp number via your connected instance.",
                "summary": "Send Text Message",
                "tags": [
                    "WhatsApp"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "instanceName": {
                                        "type": "string"
                                    },
                                    "number": {
                                        "type": "string"
                                    },
                                    "text": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "instanceName",
                                    "number",
                                    "text"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "integer",
                                    "enum": [
                                        200
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            }
        },
        "/whatsapp/messages/media": {
            "post": {
                "operationId": "whatsApp.sendMediaMessage",
                "description": "Send an image, video, audio, or document (PDF, etc.) to a WhatsApp number.",
                "summary": "Send Media Message",
                "tags": [
                    "WhatsApp"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "instanceName": {
                                        "type": "string"
                                    },
                                    "number": {
                                        "type": "string"
                                    },
                                    "mediatype": {
                                        "type": "string",
                                        "enum": [
                                            "image",
                                            "video",
                                            "audio",
                                            "document"
                                        ]
                                    },
                                    "media": {
                                        "type": "string"
                                    },
                                    "caption": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "fileName": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    }
                                },
                                "required": [
                                    "instanceName",
                                    "number",
                                    "mediatype",
                                    "media"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "integer",
                                    "enum": [
                                        200
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/AuthenticationException"
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "http": {
                "type": "http",
                "scheme": "bearer"
            }
        },
        "responses": {
            "AuthenticationException": {
                "description": "Unauthenticated",
                "content": {
                    "application/json": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "message": {
                                    "type": "string",
                                    "description": "Error overview."
                                }
                            },
                            "required": [
                                "message"
                            ]
                        }
                    }
                }
            }
        }
    }
}