{"openapi":"3.1.0","info":{"title":"Senda SMS API","version":"1.0.0","description":"Multi-tenant SMS for South African businesses. Authenticate with `Authorization: Bearer sk_live_…` (or `sk_test_…` for the sandbox)."},"servers":[{"url":"https://api.sendaapp.co.za"}],"tags":[{"name":"SMS Messaging","description":"One-off and batch sends with automatic GSM-7/UCS-2 segmentation, idempotency keys, delivery tracking and failover across aggregators. Use an sk_test_ key to send to the sandbox without charge to real handsets."},{"name":"Contacts & Lists","description":"Store contacts with the consent basis you collected, group them into lists, import CSVs of up to 100 000 rows and honour opt-outs automatically at send time."},{"name":"Templates & Campaigns","description":"Templates with {{first_name}} placeholders, campaigns to a list with scheduling, pause/cancel and live stats. Marketing sends wait for WASPA hours (Mon–Fri 08:00–20:00, Sat 09:00–13:00) and require an opt-out instruction."},{"name":"Webhooks & Events","description":"Subscribe to message.submitted, message.failed, contact.opted_out, campaign.completed, queue.alert, balance.low. Every request carries X-Timestamp and X-Signature: sha256=HMAC(secret, \"<timestamp>.<body>\"). Failed deliveries retry 8 times over ~23 hours, then land in a dead-letter list you can replay."},{"name":"Account, Usage & Billing","description":"Prepaid balance and plan bundle, usage by day, campaign and API key (the same numbers your invoices use), and invoice PDFs."},{"name":"Zapier, Make & REST hooks","description":"Connect with an API key. Triggers use REST-hook subscriptions (instant), actions call the public API. The same endpoints work for any iPaaS."}],"paths":{"/v1/messages":{"post":{"operationId":"sendMessage","summary":"Send an SMS","tags":["SMS Messaging"],"description":"Required scopes: messages:write","security":[{"apiKey":["messages:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"to":{"type":"string","minLength":3,"maxLength":32},"from":{"type":"string","minLength":1,"maxLength":16},"body":{"type":"string","minLength":1,"maxLength":1600},"client_ref":{"type":"string","minLength":1,"maxLength":128},"category":{"type":"string","enum":["transactional","marketing"],"default":"transactional"}},"required":["to","from","body"],"additionalProperties":false},"example":{"to":"0821234567","from":"ACME","body":"Your order #1042 has shipped.","client_ref":"order-1042"}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"example":{"id":"01a19900-0000-7000-8000-00000000abcd","direction":"out","to":"+27821234567","from":"ACME","body":"Your order #1042 has shipped.","parts":1,"encoding":"gsm7","status":"queued","category":"transactional","campaign_id":null,"client_ref":"order-1042","provider":null,"provider_message_id":null,"error_code":null,"cost_cents":0,"test":false,"created_at":"2026-11-01T08:00:00.000Z","sent_at":null,"delivered_at":null}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"listMessages","summary":"List messages","tags":["SMS Messaging"],"description":"Required scopes: messages:read","security":[{"apiKey":["messages:read"]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["queued","submitted","sent","delivered","failed","undelivered","expired","received"]}},{"name":"since","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"data":[{"id":"01a19900-0000-7000-8000-00000000abcd","direction":"out","to":"+27821234567","from":"ACME","body":"Your order #1042 has shipped.","parts":1,"encoding":"gsm7","status":"queued","category":"transactional","campaign_id":null,"client_ref":"order-1042","provider":null,"provider_message_id":null,"error_code":null,"cost_cents":0,"test":false,"created_at":"2026-11-01T08:00:00.000Z","sent_at":null,"delivered_at":null}],"next_cursor":null}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/messages/batch":{"post":{"operationId":"sendBatch","summary":"Send up to 1 000 SMS in one call","tags":["SMS Messaging"],"description":"Required scopes: messages:write","security":[{"apiKey":["messages:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"messages":{"type":"array","items":{"type":"object","properties":{"to":{"type":"string","minLength":3,"maxLength":32},"from":{"type":"string","minLength":1,"maxLength":16},"body":{"type":"string","minLength":1,"maxLength":1600},"client_ref":{"type":"string","minLength":1,"maxLength":128},"category":{"type":"string","enum":["transactional","marketing"],"default":"transactional"}},"required":["to","from","body"],"additionalProperties":false},"minItems":1,"maxItems":1000}},"required":["messages"],"additionalProperties":false},"example":{"messages":[{"to":"+27821234567","from":"ACME","body":"Hi Thandi, your appointment is tomorrow at 10:00."},{"to":"+27831234567","from":"ACME","body":"Hi Pieter, your appointment is tomorrow at 11:00."}]}}}},"responses":{"207":{"description":"Success","content":{"application/json":{"example":{"accepted":2,"rejected":0,"results":[{"index":0,"status":202,"message":{"id":"01a19900-0000-7000-8000-00000000abcd","direction":"out","to":"+27821234567","from":"ACME","body":"Your order #1042 has shipped.","parts":1,"encoding":"gsm7","status":"queued","category":"transactional","campaign_id":null,"client_ref":"order-1042","provider":null,"provider_message_id":null,"error_code":null,"cost_cents":0,"test":false,"created_at":"2026-11-01T08:00:00.000Z","sent_at":null,"delivered_at":null}}]}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/messages/{id}":{"get":{"operationId":"getMessage","summary":"Get a message and its status","tags":["SMS Messaging"],"description":"Required scopes: messages:read","security":[{"apiKey":["messages:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"id":"01a19900-0000-7000-8000-00000000abcd","direction":"out","to":"+27821234567","from":"ACME","body":"Your order #1042 has shipped.","parts":1,"encoding":"gsm7","status":"submitted","category":"transactional","campaign_id":null,"client_ref":"order-1042","provider":"smsflow","provider_message_id":null,"error_code":null,"cost_cents":0,"test":false,"created_at":"2026-11-01T08:00:00.000Z","sent_at":null,"delivered_at":null}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/messages/{id}/events":{"get":{"operationId":"messageEvents","summary":"Full status history","tags":["SMS Messaging"],"description":"Required scopes: messages:read","security":[{"apiKey":["messages:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"data":[{"id":"…","status":"submitted","error_code":null,"provider":"smsflow","occurred_at":"2026-11-01T08:00:01.000Z","raw":{}}]}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/contacts":{"post":{"operationId":"createContact","summary":"Create or update a contact","tags":["Contacts & Lists"],"description":"Required scopes: contacts:write","security":[{"apiKey":["contacts:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"msisdn":{"type":"string","minLength":3,"maxLength":32},"name":{"type":"string","maxLength":200,"nullable":true},"attributes":{"type":"object","additionalProperties":{"anyOf":[{"type":"string","maxLength":500},{"type":"number"},{"type":"boolean"},{"enum":["null"],"nullable":true}]}},"consent_source":{"type":"string","minLength":2,"maxLength":100},"list_ids":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":50}},"required":["msisdn"],"additionalProperties":false},"example":{"msisdn":"0821234567","name":"Thandi Nkosi","attributes":{"first_name":"Thandi","branch":"Sandton"},"consent_source":"web_form"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"example":{"id":"…","msisdn":"+27821234567","name":"Thandi Nkosi","attributes":{"first_name":"Thandi"},"consent_source":"web_form","opted_out_at":null}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"listContacts","summary":"Search contacts","tags":["Contacts & Lists"],"description":"Required scopes: contacts:read","security":[{"apiKey":["contacts:read"]}],"parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":100}},{"name":"list_id","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"opted_out","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"data":[],"next_cursor":null}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/contacts/{id}/opt-out":{"post":{"operationId":"optOutContact","summary":"Opt a contact out","tags":["Contacts & Lists"],"description":"Required scopes: contacts:write","security":[{"apiKey":["contacts:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"id":"…","opted_out_at":"2026-11-01T09:00:00.000Z"}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/lists":{"post":{"operationId":"createList","summary":"Create a list","tags":["Contacts & Lists"],"description":"Required scopes: contacts:write","security":[{"apiKey":["contacts:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100}},"required":["name"],"additionalProperties":false},"example":{"name":"Loyalty members"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"example":{"id":"…","name":"Loyalty members","members":0}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/templates":{"post":{"operationId":"createTemplate","summary":"Create a template","tags":["Templates & Campaigns"],"description":"Required scopes: templates:write","security":[{"apiKey":["templates:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"body":{"type":"string","minLength":1,"maxLength":1600},"category":{"type":"string","enum":["transactional","marketing"],"default":"marketing"}},"required":["name","body"],"additionalProperties":false},"example":{"name":"November promo","body":"Hi {{first_name}}, 20% off this weekend at ACME. Reply STOP to opt out.","category":"marketing"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"example":{"id":"…","name":"November promo","variables":["first_name"]}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/campaigns":{"post":{"operationId":"createCampaign","summary":"Create a campaign","tags":["Templates & Campaigns"],"description":"Required scopes: campaigns:write","security":[{"apiKey":["campaigns:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"template_id":{"type":"string","format":"uuid"},"list_id":{"type":"string","format":"uuid"},"sender":{"type":"string","minLength":1,"maxLength":16}},"required":["name","template_id","list_id","sender"],"additionalProperties":false},"example":{"name":"November promo","template_id":"…","list_id":"…","sender":"ACME"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"example":{"id":"…","status":"draft","total_recipients":1200}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/campaigns/{id}/schedule":{"post":{"operationId":"scheduleCampaign","summary":"Start or schedule a campaign","tags":["Templates & Campaigns"],"description":"Required scopes: campaigns:write","security":[{"apiKey":["campaigns:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"scheduled_at":{"type":"string","format":"date-time"}},"additionalProperties":false},"example":{"scheduled_at":"2026-11-06T09:00:00+02:00"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"id":"…","status":"scheduled"}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/campaigns/{id}/stats":{"get":{"operationId":"campaignStats","summary":"Campaign progress","tags":["Templates & Campaigns"],"description":"Required scopes: campaigns:read","security":[{"apiKey":["campaigns:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"total":1200,"submitted":1150,"failed":20,"queued":30}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/webhooks":{"post":{"operationId":"createWebhook","summary":"Register a webhook (returns the signing secret once)","tags":["Webhooks & Events"],"description":"Required scopes: webhooks:write","security":[{"apiKey":["webhooks:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2000},"events":{"type":"array","items":{"type":"string","enum":["message.submitted","message.delivered","message.undelivered","message.failed","message.received","contact.opted_out","campaign.completed","queue.alert","balance.low"]},"minItems":1},"description":{"type":"string","maxLength":200},"enabled":{"type":"boolean","default":true}},"required":["url","events"],"additionalProperties":false},"example":{"url":"https://example.co.za/senda/webhooks","events":["message.delivered","message.failed","message.received"]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"example":{"id":"…","url":"https://example.co.za/senda/webhooks","events":["message.delivered"],"secret":"whsec_…"}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/webhooks/{id}/test":{"post":{"operationId":"testWebhook","summary":"Send a signed test event","tags":["Webhooks & Events"],"description":"Required scopes: webhooks:write","security":[{"apiKey":["webhooks:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Success","content":{"application/json":{"example":{"delivery_id":"…"}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/webhooks/{id}/deliveries":{"get":{"operationId":"webhookDeliveries","summary":"Delivery log (incl. dead letters)","tags":["Webhooks & Events"],"description":"Required scopes: webhooks:read","security":[{"apiKey":["webhooks:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"data":[{"id":"…","event":"message.delivered","attempts":1,"state":"delivered","last_status":200}]}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/account/balance":{"get":{"operationId":"balance","summary":"Current balance","tags":["Account, Usage & Billing"],"security":[{"apiKey":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"balance_cents":48530,"bundle_parts_remaining":1200,"currency":"ZAR"}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/account/usage":{"get":{"operationId":"usage","summary":"Usage report","tags":["Account, Usage & Billing"],"description":"Required scopes: account:read","security":[{"apiKey":["account:read"]}],"parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"totals":{"messages":18342,"parts":19020,"cost_cents":551580,"bundle_parts":10000},"by_day":[]}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/account/invoices":{"get":{"operationId":"invoices","summary":"Invoices","tags":["Account, Usage & Billing"],"description":"Required scopes: account:read","security":[{"apiKey":["account:read"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"example":{"data":[{"id":"…","number":"INV-001042","total_cents":199900,"status":"paid"}]}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/hooks":{"post":{"operationId":"subscribeHook","summary":"Subscribe a REST hook","tags":["Zapier, Make & REST hooks"],"description":"Required scopes: webhooks:write","security":[{"apiKey":["webhooks:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"target_url":{"type":"string","format":"uri","maxLength":2000},"event":{"type":"string","enum":["message.submitted","message.delivered","message.undelivered","message.failed","message.received","contact.opted_out","campaign.completed","queue.alert","balance.low"]},"source":{"type":"string","enum":["zapier","make"],"default":"zapier"}},"required":["target_url","event"],"additionalProperties":false},"example":{"target_url":"https://hooks.zapier.com/hooks/standard/123/abc","event":"message.received","source":"zapier"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"example":{"id":"…","event":"message.received","secret":"whsec_…"}}}},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/hooks/{id}":{"delete":{"operationId":"unsubscribeHook","summary":"Unsubscribe a REST hook","tags":["Zapier, Make & REST hooks"],"description":"Required scopes: webhooks:write","security":[{"apiKey":["webhooks:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Success"},"default":{"description":"Error (RFC 9457 problem+json)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"sk_live_… / sk_test_…"}},"schemas":{"Problem":{"type":"object","required":["type","title","status","code"],"properties":{"type":{"type":"string"},"title":{"type":"string"},"status":{"type":"integer"},"code":{"type":"string","enum":["validation_failed","invalid_msisdn","body_too_long","unauthenticated","insufficient_credit","forbidden","insufficient_scope","sender_id_not_approved","tenant_suspended","recipient_opted_out","not_found","idempotency_conflict","invalid_signature","unknown_provider","rate_limited","weak_password","invalid_token","email_not_verified","tenant_not_verified","account_locked","mfa_invalid","mfa_step_up_required","mfa_not_enabled","ip_not_allowed","unsafe_url","conflict","plan_limit","invalid_state","outside_send_window","payment_provider_error","payments_not_configured","integration_not_configured","payload_too_large","internal_error"]},"detail":{"type":"string"},"instance":{"type":"string"}}}}}}