Long-poll for new events
GET /v1/events/wait
Holds the request until an event newer than cursor exists or timeout seconds pass, then returns the new events oldest first and the cursor to send next. Call once without cursor to get one that means "from now" (answers immediately, empty). An event can be returned more than once: de-duplicate by id. Reads the event log only: no webhook endpoint is called and no delivery is recorded. This is what simplesms listen runs on. Rate limit: 600 requests per 5 minutes, separate from other calls. Scope: webhooks.
Send your API key as a bearer token: Authorization: Bearer ssms_sk_.... Test keys run this endpoint against the sandbox; see Authentication for key modes and scopes.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
cursor | string | No | The cursor of the previous response. Omit on the first call. |
timeout | integer | No | Seconds to hold the request. Default 20. Maximum 25. Minimum 0. |
Results are paged. When has_more is true, pass next_cursor from the response as cursor to fetch the next page.
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | New events, oldest first | Page of Event |
| 401 | Missing, malformed, or revoked API key | Error |
| 402 | Billable live calls only: the prepaid credit balance cannot cover the call (insufficient_credits); nothing was done or charged | Error |
| 429 | Rate limit or quota exceeded | Error |
200: each item in data (Event)
The body is a page: data (the array), has_more, and next_cursor (null on the last page).
| Field | Type | Description |
|---|---|---|
id | string | Example: evt_a1B2c3D4e5F6g7H8. |
object | event | |
type | message.sent, message.delivered, message.failed, message.received, message.opted_out, message.opted_in, message.help_requested, message.blocked, broadcast.complete, number.purchased, number.released, number.sender_updated, verification.sent, verification.approved, verification.failed, verification.blocked, verification.sent_to_opted_out, registration.updated, deliverability.degraded, spend.threshold_reached, credits.low, credits.depleted, credits.topped_up, credits.auto_recharge_failed, automation.run.started, automation.run.completed, automation.run.failed, schedule.occurrence_skipped, schedule.paused, batch.created, batch.paused, batch.resumed, batch.canceled, batch.retried, batch.complete | |
created_at | string (date-time) | |
data | object |
Errors
| Status | When |
|---|---|
| 401 | Missing, malformed, or revoked API key |
| 402 | Billable live calls only: the prepaid credit balance cannot cover the call (insufficient_credits); nothing was done or charged |
| 429 | Rate limit or quota exceeded |
Every error has the same JSON shape, and request_id matches the X-Request-Id response header. Errors lists every code and what to do about it.
{
"error": {
"code": "invalid_request",
"message": "What went wrong, in plain words.",
"param": "the_field",
"request_id": "req_a1B2c3D4e5F6g7H8"
}
}Examples
curl
curl -X GET "https://api.joinsimplesms.com/v1/events/wait" \
-H "Authorization: Bearer $SIMPLESMS_API_KEY"Node.js
The Node.js SDK does not wrap this endpoint yet; call it with fetch.
const res = await fetch('https://api.joinsimplesms.com/v1/events/wait', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.SIMPLESMS_API_KEY}`,
},
});
if (!res.ok) throw new Error((await res.json()).error.message);
const data = await res.json();Python
The Python SDK does not wrap this endpoint yet; call it over HTTP.
import json, os, urllib.request
req = urllib.request.Request(
"https://api.joinsimplesms.com/v1/events/wait",
method="GET",
headers={
"Authorization": f"Bearer {os.environ['SIMPLESMS_API_KEY']}",
},
)
with urllib.request.urlopen(req) as res:
data = json.load(res)