Introduction
Ersaal REST API — send SMS, verify OTP, and manage your project
Overview
The Ersaal API is a RESTful service that lets you send SMS messages, verify one-time passwords, and manage your project programmatically.
Base URL
https://sms.lamah.comAll requests must be made over HTTPS. Every request requires an Authorization header with a Bearer token.
What you can do
| Category | Endpoints |
|---|---|
| SMS | Send single, bulk, template, and group messages |
| OTP | Initiate and verify one-time passwords |
| Project | Get details, balance, contacts, and usage stats |
Request format
All requests must include:
Content-Type: application/json
Accept: application/json
Authorization: Bearer YOUR_API_TOKENSend Accept: application/json on every request. It is not optional: without it the framework does not treat the call as an API request, and validation failures attempt an HTML redirect instead of returning the JSON 422 documented here. A bare Accept: */* — what most HTTP clients send by default — is not sufficient.
Idempotency
The four send endpoints accept an optional Idempotency-Key header:
Idempotency-Key: order-4471-shippedRetrying with the same key and the same request body returns the original message_id and cost without sending again. Reusing a key with a different body returns 409. Keys are remembered for 24 hours and are scoped to your project.
Response format
All responses are JSON. Successful responses return a 2xx status. The shape depends on the endpoint:
- Send endpoints return a flat object, e.g.
{ "message_id": "...", "cost": 1 } - List endpoints wrap a Laravel paginator in a
datakey - Get Message returns an array containing a single message object
Every error returns a message field. Validation failures (422) additionally include a field-keyed errors object:
{
"message": "The receiver must be valid in system providers.",
"errors": {
"receiver": ["The receiver must be valid in system providers."]
}
}There is no machine-readable code field in error responses. Branch on the HTTP status code, and on message only when you need to distinguish two errors that share a status.
Rate limits
| Endpoint group | Limit |
|---|---|
| OTP initiate | 10 requests / hour per phone number, per project |
| OTP verify | Not rate limited, but each request_id allows only 3 wrong guesses before the OTP is invalidated |
| Everything else | No fixed request-rate limit |
Sending is instead bounded by your wallet balance or subscription quota. When the OTP send limit is hit the response is 429 with a Retry-After header (in seconds); no X-RateLimit-* headers are returned.
Exhausting the verification attempts also returns 429, but without Retry-After and without any possibility of retry — see the two kinds of 429.
Get your API token from the dashboard under Projects → Project Details.