SMS and Conversations
Two ways to send, one inbox to read. Send SMS from a receptionist's number or from your tenant's dedicated outbound number, then work replies through the conversations inbox.
Direct send
From a receptionist
POST /api/v1/receptionists/:id/sms sends an SMS from the receptionist's phone number.
{
"to": "+12125551234",
"message": "Your appointment is confirmed!"
}
Both fields are required. to must be E.164; message is capped at 1600 characters.
{
"id": "msg_abc123",
"status": "sent",
"to": "+12125551234",
"from": "+16145551234",
"message": "Your appointment is confirmed!",
"sent_at": "2026-03-11T15:00:00Z"
}
GET /api/v1/receptionists/:id/sms returns paginated SMS history for the receptionist, with limit (1-100, default 20), cursor, and phone (filter by contact phone number) query parameters.
From your dedicated outbound number
POST /api/v1/sms/send sends from your tenant's dedicated outbound number. Use this when you don't need a receptionist context, such as reminders, customer replies, or agent-driven texts. Scope: send_sms.
{
"to": "+12125551234",
"message": "Hi there! See you tomorrow.",
"lead_id": "uuid"
}
to and message (max 1600 characters) are required; lead_id optionally associates the message with a lead.
{
"id": "msg_abc123",
"status": "sent",
"from": "+16145551234",
"to": "+12125551234",
"message": "Hi there! See you tomorrow.",
"provider": "telnyx",
"sent_at": "2026-04-20T15:00:00Z"
}
Opt-outs return 422
The API checks opt-out status before every send. If the recipient has texted STOP, the request returns 422 and you must skip that contact. Opt-outs cannot be overridden via the API; the customer must text START to re-subscribe.
Conversations (inbox)
Every conversation is tenant-scoped and keyed by the customer's E.164 phone number.
List conversations
GET /api/v1/conversations lists inbox conversations. Keyset-paginated, newest first.
| Parameter | Description |
|---|---|
limit | Integer, 1-100, default 50 |
cursor | From a previous response |
status | active, closed, archived, or opted_out |
phone | Exact E.164 match, e.g. +12125551234 |
{
"data": [
{
"id": "uuid",
"customer_phone": "+12125551234",
"customer_name": "Jane Doe",
"status": "active",
"unread_count": 2,
"has_inbound": true,
"last_message_at": "2026-04-22T14:10:00Z",
"intent_score": "warm",
"intent_summary": "Wants a quote for water heater install",
"ai_chatbot_active": true,
"created_at": "2026-04-20T10:00:00Z",
"updated_at": "2026-04-22T14:10:00Z"
}
],
"has_more": false
}
Get a conversation
GET /api/v1/conversations/:id returns the conversation with its 20 most recent messages inline (oldest first within the page).
{
"id": "uuid",
"customer_phone": "+12125551234",
"customer_name": "Jane Doe",
"status": "active",
"unread_count": 0,
"messages": [
{
"id": "uuid",
"direction": "inbound",
"from_phone": "+12125551234",
"to_phone": "+16145550000",
"body": "Hey, is this still available?",
"status": "received",
"segments": 1,
"created_at": "2026-04-22T14:09:40Z"
}
]
}
Message history for a thread
GET /api/v1/conversations/:id/messages returns paginated message history for one conversation. Keyset-paginated, newest first. Use limit and cursor.
{
"data": [
{
"id": "uuid",
"conversation_id": "uuid",
"campaign_id": null,
"direction": "outbound",
"from_phone": "+16145550000",
"to_phone": "+12125551234",
"body": "Thanks, talk soon!",
"status": "delivered",
"segments": 1,
"cost_cents": 1,
"ai_handled": false,
"created_at": "2026-04-22T14:12:00Z"
}
],
"has_more": true,
"cursor": "eyJjcmVhdGVkX2F0IjoiMjAyNi0w..."
}
Reply into a conversation
POST /api/v1/conversations/:id/reply sends an SMS reply into an existing conversation. Scope: send_sms. The recipient is resolved from the conversation row, so no to field is required. The from-number is your tenant's dedicated SMS number. Respects opt-outs (422).
{
"message": "We have an 8am slot tomorrow if that works."
}
{
"id": "provider-message-id",
"conversation_id": "uuid",
"status": "sent",
"from": "+16145550000",
"to": "+12125551234",
"message": "We have an 8am slot tomorrow if that works.",
"provider": "telnyx",
"sent_at": "2026-04-22T14:20:00Z"
}
The compliance footer cannot be suppressed via the public API.
Update conversation status
PATCH /api/v1/conversations/:id updates a conversation's status. Scope: write_crm. Valid values: open, closed, archived. open maps to the internal active state for UI compatibility. opted_out is set by inbound STOP processing only and cannot be set here.
{ "status": "closed" }
{
"id": "uuid",
"customer_phone": "+12125551234",
"status": "closed",
"updated_at": "2026-04-22T15:00:00Z"
}
Tenant-wide message feed
GET /api/v1/sms/messages returns a flat, tenant-wide message feed across every conversation. Useful for analytics and incremental sync. Keyset-paginated, newest first.
| Parameter | Description |
|---|---|
limit | Integer, 1-100, default 50 |
cursor | From a previous response |
direction | inbound or outbound |
since | ISO 8601 timestamp, e.g. 2026-04-01T00:00:00Z |
curl -H "Authorization: Bearer $AUTOREV_API_KEY" \
"https://app.autorev.ai/api/v1/sms/messages?direction=inbound&since=2026-04-20T00:00:00Z"
{
"data": [
{
"id": "uuid",
"conversation_id": "uuid",
"campaign_id": null,
"direction": "inbound",
"from_phone": "+12125551234",
"to_phone": "+16145550000",
"body": "Yes please",
"status": "received",
"segments": 1,
"created_at": "2026-04-22T09:05:00Z"
}
],
"has_more": false
}