Complete REST API reference — authentication, SMS, contacts, billing, and the Zapier integration surface used by our published Zapier app.
ReadySMS exposes a REST API over HTTPS. Every response is JSON with a top-level success boolean; success responses include a data field, error responses include an error string.
https://api.readysms.io
All endpoints below are relative to this base URL. The API is owned and operated by ReadySMS — the same team behind readysms.io and app.readysms.io. There is no sandbox or staging environment; all documented endpoints are production.
Two authentication methods are supported. Use OAuth 2.0 for third-party integrations (Zapier, partner apps). Use API keys for direct server-to-server calls owned by the account holder.
Used by the published Zapier integration. See the Zapier OAuth section for the full flow. Access tokens returned by /zapier/oauth/token are JWTs; pass them in Authorization: Bearer <token> on every subsequent request.
POST /sms/send (and all bulk send endpoints) must include "consent_attested": true in the JSON body. This certifies you have prior express written consent from each recipient under the TCPA.
HTTP 403 with error_code: "api_consent_attested_required". Dashboard sends are unaffected — they have their own attestation flow.
Personal API keys are generated from Settings → API Keys in the dashboard. Pass either as a bearer token or an X-API-Key header:
Authorization: Bearer rsms_your_api_key_here X-API-Key: rsms_your_api_key_here
Keys prefixed rsms_ are general API keys; keys prefixed zap_ are Zapier-scoped keys generated via POST /zapier/api-keys.
Send messages, query message history, and generate AI-written copy.
true — certifies the recipient gave prior express written consent under TCPA. required{
"to": "+14155551234",
"message": "Hello from ReadySMS!",
"consent_attested": true,
"from_phone_number_id": 1
}
{
"success": true,
"data": {
"message_id": "abc123",
"segments": 1,
"status": "pending",
"credits_remaining": 2499
}
}
{
"success": false,
"error_code": "api_consent_attested_required",
"error": "API sends require `consent_attested: true` in the request body...",
"docs": "https://app.readysms.io/api-docs#consent"
}
// Request
{ "description": "appointment reminder for tomorrow 3pm" }
// Response
{
"success": true,
"data": [
"Hi {first_name}! Reminder: your appointment is tomorrow at 3 PM. Reply STOP to opt out.",
"Hey {first_name}, don't forget your appointment tomorrow at 3:00 PM! Reply STOP to cancel.",
"{first_name}, your appt is confirmed for tomorrow at 3 PM. See you then! Reply STOP to opt out."
]
}
Create, read, update, delete contacts.
Same fields as POST. Only include fields you want to update.
Permanently deletes the contact and all associated messages and conversations.
Query credit balance and transaction history.
{
"success": true,
"data": {
"balance": 2500,
"rate": 0.0084,
"account_type": "standard",
"daily_avg_send": 428,
"estimated_days_left": 5
}
}
Events pushed from ReadySMS to subscriber URLs (powers Zapier triggers and custom integrations).
Subscribe via POST /zapier/subscribe (see below). Payloads are JSON; see Event Payloads for the schema of each event type.
Authorization-code flow used by the published Zapier integration. Tokens returned are JWTs; use them as bearer tokens on every Zapier endpoint below.
code requiredRenders a ReadySMS-branded login/consent page. After successful login, redirects to redirect_uri with ?code=<auth_code>&state=<state>.
authorization_code or refresh_token required/authorize (for authorization_code)refresh_token)authorization_code){
"access_token": "eyJhbGciOi...",
"token_type": "Bearer",
"expires_in": 2592000,
"refresh_token": "rtk_..."
}
Same behavior as GET /zapier/auth/test. Returns the authenticated user's profile if the bearer token is valid.
Subscribe/unsubscribe hooks. Zapier calls subscribe when a Zap turns on and unsubscribe when it turns off; ReadySMS then pushes matching events to the provided target_url.
{
"success": true,
"user": {
"id": 101,
"email": "jane@example.com",
"first_name": "Jane",
"last_name": "Doe",
"company_name": "Example Realty"
}
}
{ "success": true, "data": { "id": 42 } }
The :id path parameter is the ID returned from /subscribe.
Returns an array containing one sample payload matching the shape of a live webhook delivery for the given :event. Zapier uses this during Zap setup to let the user map output fields.
Valid values for :event — any event listed in Outbound Webhooks.
Write operations exposed to Zapier users. Each action returns { success, data }.
{
"success": true,
"data": {
"message_id": "abc123",
"to": "+14155551234",
"from": "+15559876543",
"segments": 1,
"status": "sent"
}
}
Atomically debits credits before send; automatically refunds on carrier failure.
new_leadzapier)phone required)contact_id required)phone)contact_id)phone)contact_id)phone)contact_id){
"success": true,
"data": {
"enrollment_id": 10,
"contact_id": 101,
"sequence_id": 5,
"sequence_name": "7-Day Follow Up",
"next_send_at": "2026-04-16T18:00:00.000Z"
}
}
Look up existing records. Both GET and POST variants are exposed because Zapier search steps can send either.
email)phone){ "success": true, "data": [ { ...contact } ] }
Same parameters as GET variant, passed in JSON body instead of query string.
Populate Zapier's dropdown fields. Each returns an array of { id, label, ... } objects.
[{ "id": "hot-lead", "label": "hot-lead" }, ...]
[{ "id": 101, "label": "Jane Doe (+14155551234)", "phone": "+14155551234" }, ...]
[{ "id": 1, "label": "Main line", "phone_number": "+15559876543" }, ...]
[{ "id": 5, "label": "7-Day Follow Up", "name": "7-Day Follow Up" }, ...]
Shape of the JSON body POSTed to target_url when each event fires. These are also what GET /zapier/sample/:event returns for Zap setup previews.
{
"id": 12345,
"direction": "inbound",
"from_number": "+15551234567",
"to_number": "+15559876543",
"body": "Hi, I'm interested in the property at 123 Main St.",
"status": "received",
"contact_id": 101,
"contact_first_name": "John",
"contact_last_name": "Smith",
"contact_phone": "+15551234567",
"contact_email": "john@example.com",
"conversation_id": 50,
"segments": 1,
"sent_at": "2026-04-07T14:30:00.000Z"
}
{
"id": 101,
"first_name": "John",
"last_name": "Smith",
"phone": "+15551234567",
"email": "john@example.com",
"tags": ["buyer", "hot-lead"],
"pipeline_stage": "new_lead",
"source": "inbound_sms",
"status": "active",
"created_at": "2026-04-07T14:30:00.000Z"
}
{
"conversation_id": 50,
"contact_id": 101,
"first_name": "John",
"last_name": "Smith",
"phone": "+15551234567",
"email": "john@example.com",
"first_message": "Hi, I'm interested in the property at 123 Main St.",
"from_number": "+15551234567",
"to_number": "+15559876543",
"started_at": "2026-04-07T14:30:00.000Z"
}
{
"contact_id": 101,
"first_name": "Jane",
"last_name": "Doe",
"phone": "+15559876543",
"email": "jane@example.com",
"opted_out_at": "2026-04-07T14:30:00.000Z",
"keyword": "STOP"
}
{
"message_id": 12345,
"sendivo_message_id": "msg_abc123",
"from_number": "+15559876543",
"to_number": "+15551234567",
"body": "Great news! We have new listings in your area.",
"status": "delivered",
"segments": 1,
"cost": 0.0082,
"delivered_at": "2026-04-07T14:30:05.000Z",
"contact_id": 101,
"contact_first_name": "John",
"contact_last_name": "Smith"
}
{
"message_id": 12346,
"sendivo_message_id": "msg_def456",
"from_number": "+15559876543",
"to_number": "+15550000000",
"body": "Check out this listing!",
"status": "failed",
"status_description": "Undeliverable",
"segments": 1,
"cost": 0,
"delivered_at": null,
"contact_id": 102,
"contact_first_name": "Bob",
"contact_last_name": "Jones"
}
{
"contact_id": 101,
"first_name": "John",
"last_name": "Smith",
"phone": "+15551234567",
"email": "john@example.com",
"old_stage": "new_lead",
"new_stage": "qualified",
"changed_at": "2026-04-07T14:30:00.000Z"
}
{
"contact_id": 101,
"first_name": "John",
"last_name": "Smith",
"phone": "+15551234567",
"email": "john@example.com",
"tag": "hot-lead",
"all_tags": ["buyer", "hot-lead"],
"added_at": "2026-04-07T14:30:00.000Z"
}
{
"contact_id": 101,
"first_name": "John",
"last_name": "Smith",
"phone": "+15551234567",
"email": "john@example.com",
"tag": "hot-lead",
"all_tags": ["buyer"],
"removed_at": "2026-04-07T14:30:00.000Z"
}
{
"contact_id": 101,
"first_name": "John",
"last_name": "Smith",
"phone": "+15551234567",
"email": "john@example.com",
"dnd_sms": true,
"changed_at": "2026-04-07T14:30:00.000Z"
}
{
"contact_id": 101,
"first_name": "John",
"last_name": "Smith",
"phone": "+15551234567",
"email": "john@example.com",
"sequence_id": 5,
"sequence_name": "7-Day Follow Up",
"completed_at": "2026-04-07T14:30:00.000Z"
}
{
"contact_id": 101,
"first_name": "John",
"last_name": "Smith",
"phone": "+15551234567",
"email": "john@example.com",
"keyword": "YES",
"body": "Yes I am interested",
"from_number": "+15551234567",
"to_number": "+15559876543",
"received_at": "2026-04-07T14:30:00.000Z"
}
Email our integration team — we typically reply within one business day.
support@readysms.io · Help Center · DashboardReadySMS · United States