API reference/phone

Receive delivery status webhooks from an SMS provider

POST/api/v1/phone/feedback/{provider}/{feedbackKey}

authentication
Feedback key in the URL
billing
Free.

The webhook target for an SMS provider's delivery status callbacks, the phone counterpart of the email bounce webhook. Providers cannot send bearer tokens, so the account's feedback key rides in the URL (the same key as for email, generated or rotated on the dashboard); the provider name picks the payload adapter. Twilio and MessageBird post form fields, Vonage and Sinch JSON; both are read. Only definitive statuses become outcomes; queued, sent, buffered, accepted and unknown are ignored.

Provider Path Mapping
twilio /api/v1/phone/feedback/twilio/{key} Message status callback: delivered → delivered · undelivered and failed → undelivered. To is the number; the callback carries no timestamp, so the outcome is dated on receipt.
vonage /api/v1/phone/feedback/vonage/{key} SMS API receipts (msisdn, status, message-timestamp) and Messages API status webhooks (to, status, timestamp): delivered → delivered · expired, failed, rejected and undeliverable → undelivered.
messagebird /api/v1/phone/feedback/messagebird/{key} Status reports (recipient, status, statusDatetime), configured as POST: delivered → delivered · delivery_failed and expired → undelivered.
sinch /api/v1/phone/feedback/sinch/{key} Per-recipient reports (recipient, status, at) and batch reports (statuses[].recipients): Delivered → delivered · Failed, Expired, Rejected and Aborted → undelivered.

Throttled at 120 requests per minute per IP. Outcomes recorded here behave exactly like ones reported through POST /api/v1/phone/feedback: they feed the account's own later lookups and its suppression list, and are never billed.

Parameters

name in type description
providerrequiredpathstringWhich provider's payload format to expect. One of: twilio, vonage, messagebird, sinch.
feedbackKeyrequiredpathstringThe account's feedback key, which starts with `fb_`.

Request body

The provider's native callback payload, as JSON or form fields.

Example request

curl -X POST https://spaw.co/api/v1/phone/feedback/twilio/fb_… \
  -H "Content-Type: application/json" \
  -d '{
  "MessageSid": "SM0f2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
  "To": "+447911012345",
  "MessageStatus": "undelivered",
  "ErrorCode": "30003"
}'
const response = await fetch('https://spaw.co/api/v1/phone/feedback/twilio/fb_…', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "MessageSid": "SM0f2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    "To": "+447911012345",
    "MessageStatus": "undelivered",
    "ErrorCode": "30003"
  }),
});
const result = await response.json();
import requests

response = requests.post(
    'https://spaw.co/api/v1/phone/feedback/twilio/fb_…',
    json={
        'MessageSid': 'SM0f2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d',
        'To': '+447911012345',
        'MessageStatus': 'undelivered',
        'ErrorCode': '30003'
    },
)
result = response.json()
$ch = curl_init('https://spaw.co/api/v1/phone/feedback/twilio/fb_…');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode([
        'MessageSid' => 'SM0f2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d',
        'To' => '+447911012345',
        'MessageStatus' => 'undelivered',
        'ErrorCode' => '30003'
    ]),
]);
$result = json_decode(curl_exec($ch), true);

Responses

200The outcomes the payload carried were recorded.

{
    "success": true,
    "data": {
        "recorded": 1,
        "skipped": 0
    }
}

401The feedback key does not exist or was rotated.

{
    "success": false,
    "error": {
        "code": "INVALID_FEEDBACK_KEY",
        "message": "That feedback key does not exist or was rotated.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}

404The provider path is not one of twilio, vonage, messagebird, or sinch.

{
    "success": false,
    "error": {
        "code": "UNKNOWN_FEEDBACK_PROVIDER",
        "message": "Supported providers: twilio, vonage, messagebird, sinch.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}

429Over 5 requests per second for the key. Retry after the limit resets.

{
    "success": false,
    "error": {
        "code": "RATE_LIMITED",
        "message": "Too many requests. Retry after the limit resets.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}

Error codes

Failures answer { success: false, error: { code, message, request_id } }. Each code has its own page.

markdown version·openapi.json