Onsidian API
Recruiting

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:

FieldDescription
FromThe recruit's phone number (E.164)
ToThe Twilio phone number that received the message
BodyThe text content of the message
MessageSidTwilio's unique message identifier

Behavior

  1. The conversation is looked up by matching From (recruit phone) and To (Twilio phone) against the recruiting_conversations table.
  2. If no conversation is found, the endpoint returns { "status": "no_conversation" } without error.
  3. The message is stored in recruiting_messages with direction: "inbound" and sender_type: "recruit".
  4. If the conversation status is "bot", an automated LLM response will be generated and sent (not yet implemented).
  5. 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:

FieldDescription
MessageSidTwilio's unique message identifier
MessageStatusTwilio delivery status string

Status mapping

Twilio statusStored status
queuedqueued
sentsent
delivereddelivered
undeliveredfailed
failedfailed

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" }

On this page