Skip to main content

SMS

Send transactional SMS, top up a prepaid wallet, and inspect delivery history. All endpoints are scoped to your API key's supplier.

Required scopes:

  • sms:read — list messages, view wallet balance + transactions, view pricing
  • sms:write — send SMS, initiate Stripe top-ups

List SMS Messages​

GET /api/v1/sms-messages

Returns paginated SMS history for your supplier, newest first.

Query Parameters​

ParameterTypeDescription
statusstringFilter by status: queued, sending, sent, delivered, failed, undelivered, insufficient_balance
initiated_bystringFilter by who triggered the send: user, ai, system
booking_idintFilter to one booking
fromISO 8601 dateStart of date range
toISO 8601 dateEnd of date range
per_pageintDefault 25

Response​

{
"data": [
{
"id": 142,
"supplier_id": 1,
"customer_id": 56,
"booking_id": 789,
"notification_name": "upcoming_booking",
"to_phone": "+1•••••2671",
"destination_country": "US",
"body_preview": "Reminder: your Coastal Adventures booking…",
"status": "delivered",
"segments": 1,
"twilio_sid": "SM…",
"charged_cents": 3,
"twilio_cost_cents": 2,
"initiated_by": "system",
"sent_at": "2026-05-05T14:00:00+00:00",
"delivered_at": "2026-05-05T14:00:03+00:00"
}
],
"meta": { "request_id": "...", "current_page": 1, "total": 142 }
}

Phone numbers are masked by default — only the country code and last 4 digits are exposed.


Send Ad-Hoc SMS​

POST /api/v1/sms-messages

Sends a custom SMS to a customer. Wallet is debited immediately on success.

Request Body​

FieldTypeRequiredDescription
customer_idintyesCustomer in your supplier scope
bodystringyesMessage body (max ~10 segments after auto-trim per sms.max_segments_per_message)
notification_namestringnoAudit-log tag, default api_adhoc
booking_idintnoLink to a booking

Response​

201 Created with the resulting SMS message resource.

Errors​

  • 402 Payment Required — wallet has insufficient balance
  • 422 Unprocessable Entity — customer opted out, phone unparseable, or validation failed

Wallet Balance​

GET /api/v1/sms-wallet/balance
{
"data": {
"balance_cents": 2340,
"low_balance": false,
"critically_low": false,
"low_balance_threshold_cents": 500
}
}

Initiate Wallet Top-Up​

POST /api/v1/sms-wallet/topups

Creates a Stripe Checkout session for an arbitrary top-up amount. Returns the URL to redirect the supplier to. The wallet is credited via webhook only after the supplier completes payment — the top-up is recorded as pending until then.

Request Body​

FieldTypeRequiredDescription
amount_centsintyes$5 minimum (500), $500 maximum (50000) per top-up

Response​

{
"data": { "checkout_url": "https://checkout.stripe.com/c/pay/..." },
"meta": { ... }
}

Status code is 202 Accepted — the wallet hasn't actually been credited yet, the supplier still needs to complete checkout.


Wallet Transaction Ledger​

GET /api/v1/sms-wallet/transactions

Append-only ledger of every wallet movement. Use this for accounting reconciliation.

{
"data": [
{
"id": 99,
"type": "debit",
"amount_cents": -3,
"balance_after_cents": 2337,
"reason": "sms_send",
"sms_message_id": 142,
"sms_topup_id": null,
"created_at": "2026-05-05T14:00:00+00:00"
}
],
"meta": { ... }
}

amount_cents is signed — negative for debits, positive for credits. The denormalised suppliers.sms_wallet_balance_cents always equals the running sum of this ledger.


Per-Country Pricing​

GET /api/v1/sms-pricing

Returns the per-country rate table EquipDash uses to calculate wallet debits. Rates include the platform margin (50%) baked in and rounded up to whole cents.

{
"data": {
"margin_multiplier": 1.5,
"rates": [
{
"country": "AU",
"twilio_cost_cents": 5,
"our_cost_cents": 8,
"currency": "USD"
},
{
"country": "US",
"twilio_cost_cents": 2,
"our_cost_cents": 3,
"currency": "USD"
}
]
}
}

Rates are refreshed daily from Twilio's Pricing API. Use this endpoint to display per-country costs in your own admin UI.