Developers
Send from your own code.
A REST API to send, and signed webhooks to hear what happened next. Messages still leave through your own phones and accounts. Included with the Bundle plan.
- POST /api/v1/messages/smsyour code
- sms.queuedwebhook
- sms.sentwebhook
- sms.deliveredwebhook
- sms.received“Can I change the pickup time?”
REST API
One request sends a message.
The API lives at https://app.smsegress.com/api/v1. Create a key in your dashboard and send it as a bearer token.
curl -X POST https://app.smsegress.com/api/v1/messages/sms \ -H "Authorization: Bearer $SMSEGRESS_API_KEY" \ -H "Idempotency-Key: order-1042-ready" \ -H "Content-Type: application/json" \ -d '{"to": "+447700900123", "body": "Your order #1042 is ready for pickup."}'Keys with scopes
Each API key carries only the abilities you give it, such as sms.send, contacts.view or campaigns.manage.
Rate limits
60 requests a minute for each key, and 180 a minute across a workspace.
Safe retries
Send an Idempotency-Key header with a write, so a retry does not send twice.
| POST /messages/sms | Send an SMS through a phone or provider account |
|---|---|
| POST /messages/whatsapp | Send from a linked WhatsApp number |
| GET /messages/{id} | Read one message and its status |
| POST /messages/{id}/cancel | Cancel a message that has not left yet |
| POST /campaigns | Create a campaign |
| POST /campaigns/{id}/launch | Launch it. Pause, resume and cancel work the same way |
| PUT /contacts | Create or update a contact |
| GET /unsubscribed | List the contacts who opted out |
| GET /devices | List paired phones |
| GET /conversations | List inbox conversations |
The full reference, a request tester and an OpenAPI file are in your dashboard under API docs.
Webhooks
Then hear what happened next.
Point a webhook at your endpoint and choose the events you want. Each delivery is signed, so you can check it came from SmsEgress before you trust it.
- SMS
sms.queuedsms.sentsms.deliveredsms.failedsms.receivedwa.message.sentwa.message.receivedwaba.message.sentwaba.message.received- Contacts
contact.createdcontact.unsubscribed- Campaigns
campaign.startedcampaign.completedlink.clicked- Inbox
conversation.createdconversation.assignedconversation.resolved- Phones
device.onlinedevice.offline
Signed
X-Webhook-Signature carries a timestamp and an HMAC‑SHA256 of the timestamp, a full stop and the raw body, keyed with that webhook’s secret.
Retried
A delivery that fails is tried up to 7 times: after 1 minute, 5 minutes, 30 minutes, 3 hours, 24 hours and 72 hours.
Switched off when it is clearly broken
Answer 410 Gone and the webhook is disabled. So is one that fails 20 deliveries in a row, and the owner is told.
import { createHmac, timingSafeEqual } from 'node:crypto'; // header: X-Webhook-Signature: t=1731240000,v1=5f2c...export function verify(rawBody, header, secret) { const { t, v1 } = Object.fromEntries(header.split(',').map((p) => p.split('='))); const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex'); return v1.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected));}