SMS API

Send transactional SMS (OTP codes, alerts) worldwide with a single HTTP request. You compose the text — we deliver it to the number.

Base URL
https://sendoor.org/api/v1

Authentication

All requests are authenticated with an API key in the Authorization header. Create a key in your dashboard → API keys.

Authorization: Bearer sk_live_xxx

⚠️ Keep the key secret — it grants access to your balance. Revoke a compromised key in the dashboard.

POST/sms/send

Send SMS

Sends a single message. Charges the cost to your balance.

Body parameters (JSON)

fieldtyperequired
phonestringyesPhone number in E.164 format, e.g. +919800000000
textstringyesMessage text (delivered to the recipient as-is)
senderstringnoSender ID. Defaults to SENDOOR
referencestringnoYour identifier for idempotency (deduplication)

Request example

curl -X POST https://sendoor.org/api/v1/sms/send \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919800000000",
    "text": "Your code is 1234"
  }'

Response 201 Created

{
  "id": "8f3a1c2e-...",
  "status": "sent",
  "parts": 1,
  "price": "0.1000"
}
POST/messages/send

Send a messenger message

Deliver a message over WhatsApp, Telegram, Viber or IMO. Same billing model as SMS — you are charged the per-channel price and refunded automatically if delivery fails. Each channel is enabled separately on your API key; a key without a channel's access gets 403.

Body parameters (JSON)

fieldtyperequired
channelstringyeswhatsapp | telegram | viber | imo
phonestringyesRecipient in E.164, e.g. +919800000000
textstringyesMessage body
image_urlstringnoOptional media URL attached to the message
referencestringnoYour idempotency key (deduplicates retries)

Request example

curl -X POST https://sendoor.org/api/v1/messages/send \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "whatsapp",
    "phone": "+919800000000",
    "text": "Your code is 1234",
    "image_url": "https://example.com/pic.jpg"
  }'

Response 201 Created

{
  "id": "8f3a1c2e-...",
  "channel": "whatsapp",
  "status": "sent",
  "price": "0.0500"
}

Delivery status is retrieved the same way as SMS — GET /sms/{id}.

GET/sms/{id}

Message status

Returns the current delivery status (refreshed automatically).

curl https://sendoor.org/api/v1/sms/MESSAGE_ID \
  -H "Authorization: Bearer sk_live_xxx"

Response

{
  "id": "8f3a1c2e-...",
  "phone": "+919800000000",
  "status": "delivered",
  "parts": 1,
  "price": "0.1000",
  "reference": "order-42",
  "createdAt": "2026-06-08T12:00:00.000Z"
}
GET/balance

Balance

Your account's current balance.

curl https://sendoor.org/api/v1/balance \
  -H "Authorization: Bearer sk_live_xxx"

Response

{ "balance": "42.50", "currency": "USD" }
GET/countries

Your available countries

Returns the countries enabled for your account, with prices. Just send the full E.164 number — the country is detected automatically.

curl https://sendoor.org/api/v1/countries \
  -H "Authorization: Bearer sk_live_xxx"

Response

{
  "countries": [
    { "iso": "IN", "name": "India", "dial": "91", "price": "0.1000" }
  ],
  "defaultPrice": null,
  "currency": "USD"
}

Status values

StatusDescription
pendingAccepted, preparing to send
sentHanded to the carrier
deliveredDelivered to the recipient
failedNot delivered (error)
expiredDelivery window expired

Errors

On error, the matching HTTP code and a { error, message } body are returned.

HTTPerrorDescription
400bad_request / validationInvalid data (phone, text)
401unauthorizedMissing or invalid API key
402insufficient_fundsNot enough balance
403forbiddenKey lacks the required scope
404not_foundMessage not found
502provider_errorDelivery route error

Idempotency

Pass a unique reference field in the send request. A repeated request with the same reference won't create a duplicate or charge again — the existing message is returned. Handy for network-timeout retries.

Countries

The country is detected automatically from the number. Available destinations and prices are configured by your manager. The ISO code is the one used in pricing.

ISOCountryDial
INIndia+91
UAUkraine+380
PLPoland+48
DEGermany+49
GBUnited Kingdom+44
USUnited States+1
ESSpain+34
FRFrance+33
ITItaly+39
NLNetherlands+31
PTPortugal+351
TRTurkey+90
AEUnited Arab Emirates+971
SASaudi Arabia+966
EGEgypt+20
NGNigeria+234
KEKenya+254
ZASouth Africa+27
PKPakistan+92
BDBangladesh+880
IDIndonesia+62
PHPhilippines+63
VNVietnam+84
THThailand+66
MYMalaysia+60
SGSingapore+65
CNChina+86
JPJapan+81
KRSouth Korea+82
BRBrazil+55
MXMexico+52
ARArgentina+54
COColombia+57
CLChile+56
PEPeru+51
KZKazakhstan+7
UZUzbekistan+998
AZAzerbaijan+994
GEGeorgia+995
MDMoldova+373
RORomania+40
CZCzechia+420
SKSlovakia+421
HUHungary+36
BGBulgaria+359
GRGreece+30
ATAustria+43
CHSwitzerland+41
BEBelgium+32
SESweden+46
NONorway+47
DKDenmark+45
FIFinland+358
IEIreland+353
ILIsrael+972
QAQatar+974
KWKuwait+965
MAMorocco+212
DZAlgeria+213
GHGhana+233
AUAustralia+61
NZNew Zealand+64
CACanada+1
SMPPsendoor.org:2775

SMPP connectivity

For platforms with their own SMS engine we provide a standard SMPP 3.4 interface. Pricing, enabled countries, balance and refunds are the same as for the HTTP API — you can use both channels in parallel on a single account.

Credentials (system_id + password) are issued by your account manager. They are separate from your API key.

Connection parameters

ParameterValueNote
hostsendoor.orgTCP, no TLS
port2775
versionSMPP 3.4bind_transceiver / transmitter / receiver
system_id / passwordissued by your managerup to 2 concurrent bind sessions (can be raised)
throughput10 SMS/secdefault; exceeding it → ESME_RTHROTTLED
enquire_linkevery 30 s recommendedsupported

Notes

  • Destination numbers in international (E.164) format, e.g. 919800000000.
  • Encodings: GSM 7-bit and UCS-2 (data_coding 8) for Unicode.
  • Long SMS: concatenation via UDH (8/16-bit ref) or message_payload — parts are reassembled and billed as one message.
  • DLR: set registered_delivery=1 to receive deliver_sm with a standard receipt (stat: DELIVRD / UNDELIV / EXPIRED). Undelivered messages are refunded automatically.
  • The message_id from submit_sm_resp is the same id as in the HTTP API — you can also check status via GET /sms/{id}.

Error codes (command_status)

CodeConstantReason
0x0000000BESME_RINVDSTADRCountry not enabled for your account, or invalid number
0x00000014ESME_RMSGQFULInsufficient balance
0x00000058ESME_RTHROTTLEDThroughput limit exceeded (SMS/sec)
0x0000000EESME_RINVPASWDInvalid system_id / password
0x00000045ESME_RSUBMITFAILDelivery route error — retry later

Ready to start?

Create an account, top up your balance and generate an API key.

Sign up