SMS webhooks
Twilio webhook endpoints for inbound SMS and delivery status updates
Both endpoints validate every incoming request using Twilio's request signature. Requests that fail signature validation are rejected with UNAUTHORIZED.
POST /recruiting/sms/inbound
Receives inbound SMS messages from recruits. Called by Twilio when a message arrives on a Twilio number managed by the platform.
Authentication
Twilio request signature validation (no API key required).
Request body
Twilio sends a application/x-www-form-urlencoded form body. The following fields are used:
| Field | Description |
|---|---|
From | The recruit's phone number (E.164) |
To | The Twilio phone number that received the message |
Body | The text content of the message |
MessageSid | Twilio's unique message identifier |
Behavior
- The conversation is looked up by matching
From(recruit phone) andTo(Twilio phone) against therecruiting_conversationstable. - If no conversation is found, the endpoint returns
{ "status": "no_conversation" }without error. - The message is stored in
recruiting_messageswithdirection: "inbound"andsender_type: "recruit". - If the conversation status is
"bot", an automated LLM response will be generated and sent (not yet implemented). - If the conversation status is
"escalated", the assigned agent is notified via Supabase realtime (not yet implemented).
Response
{ "status": "received" }Twilio requires a 200 response; the endpoint always returns 200 once past signature validation.
POST /recruiting/sms/status
Receives delivery status callbacks from Twilio. Called by Twilio when the delivery status of an outbound message changes.
Authentication
Twilio request signature validation (no API key required).
Request body
Twilio sends a application/x-www-form-urlencoded form body. The following fields are used:
| Field | Description |
|---|---|
MessageSid | Twilio's unique message identifier |
MessageStatus | Twilio delivery status string |
Status mapping
| Twilio status | Stored status |
|---|---|
queued | queued |
sent | sent |
delivered | delivered |
undelivered | failed |
failed | failed |
If MessageStatus does not match any of the above values, the update is ignored and { "status": "ignored" } is returned.
Response
{ "status": "updated" }or
{ "status": "ignored" }