REST APIv1

API Documentation

Build powerful messaging integrations with the BritishText REST API. Send SMS, manage UK numbers, track deliveries, and handle inbound messages.

Get API Key

Base URL

https://api.britishtext.com/v1

Content-Type

application/json

Authentication

All API requests must be authenticated using HTTP Basic Auth with your Account SID as the username and your Auth Token as the password. You can find both in your account settings.

Authorization: Basic base64(account_sid:auth_token)

# Or Bearer token
Authorization: Bearer {auth_token}

Account SID (public)

AC_bt_xxxxxxxxxxxx

Auth Token (secret)

at_xxxxxxxxxxxxxxxxxxxxxxxxxxxx

Never expose your Auth Token in client-side code or public repositories.

Quick start

Send your first SMS in under two minutes.

curl -X POST https://api.britishtext.com/v1/messages \
  -u "AC_bt_xxxxxxxxxxxx:at_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+447911283461",
    "from": "+447700142857",
    "body": "Your appointment is confirmed for 2pm tomorrow."
  }'

Replace the example Account SID, Auth Token, and phone numbers with your own values. Use AC_test_ credentials and +447700900000 to test in the sandbox.

Messages

POST/v1/messages

Send SMS

Send an SMS message to a UK or international phone number. The sender must be a number you have rented or an approved alphanumeric sender ID.

Status flow: queued → sent → delivered | failed | undelivered. Cost is in pence (4 = £0.04 per SMS segment).

Request body parameters

ParameterTypeRequiredDescription
tostringYesRecipient phone number in E.164 format (e.g. +447911283461)
fromstringYesRented UK number (E.164) or approved alphanumeric sender ID (max 11 chars)
bodystringYesMessage text. Max 1,600 characters. Automatically segmented into multiple SMS parts.
webhook_urlstringNoOverride the account-level delivery report webhook for this message only
referencestringNoYour own reference ID for correlation (e.g. an order ID)
scheduled_atstringNoISO 8601 datetime to schedule future delivery (e.g. 2026-04-01T09:00:00Z)

Request body

{
  "to": "+447911283461",
  "from": "+447700142857",
  "body": "Your appointment is confirmed for 2pm tomorrow.",
  "reference": "appt-reminder-12345"
}

Response

{
  "id": "msg_xxxxxxxxxxxx",
  "to": "+447911283461",
  "from": "+447700142857",
  "body": "Your appointment is confirmed for 2pm tomorrow.",
  "direction": "outbound",
  "status": "queued",
  "segments": 1,
  "cost": 4,
  "currency": "GBP",
  "reference": "appt-reminder-12345",
  "created_at": "2026-03-24T10:30:00Z",
  "scheduled_at": null
}
POST/v1/messages/bulk

Send bulk SMS

Send up to 1,000 SMS messages in a single request. Returns a batch ID for tracking the overall dispatch.

Request body parameters

ParameterTypeRequiredDescription
messagesarrayYesArray of message objects, each with to, from, and body fields. Max 1,000 items.
webhook_urlstringNoDelivery report webhook applied to all messages in this batch

Request body

{
  "messages": [
    { "to": "+447911283461", "from": "+447700142857", "body": "Hi Sarah, your order is ready." },
    { "to": "+447523891024", "from": "+447700142857", "body": "Hi James, your order is ready." }
  ],
  "webhook_url": "https://app.britishtext.com/webhooks/delivery"
}

Response

{
  "batch_id": "batch_xxxxxxxxxxxx",
  "total": 2,
  "queued": 2,
  "failed": 0,
  "messages": [
    { "id": "msg_xxxxxxxxxxxx", "to": "+447911283461", "status": "queued" },
    { "id": "msg_xxxxxxxxxxxx", "to": "+447523891024", "status": "queued" }
  ]
}
GET/v1/messages

List messages

Retrieve a paginated list of sent and received messages. Supports filtering by direction, status, sender, recipient, date range, and your own reference ID.

Query parameters

ParameterTypeRequiredDescription
directionstringNoinbound or outbound
statusstringNoqueued, sent, delivered, failed, or undelivered
fromstringNoFilter by sender number (E.164)
tostringNoFilter by recipient number (E.164)
sincestringNoISO 8601 — return messages after this timestamp
untilstringNoISO 8601 — return messages before this timestamp
referencestringNoFilter by your client reference ID
limitintegerNoResults per page. Default: 20. Max: 100.
offsetintegerNoPagination offset

Response

{
  "messages": [
    {
      "id": "msg_xxxxxxxxxxxx",
      "to": "+447911283461",
      "from": "+447700142857",
      "body": "Your appointment is confirmed for 2pm tomorrow.",
      "direction": "outbound",
      "status": "delivered",
      "segments": 1,
      "cost": 4,
      "reference": "appt-reminder-12345",
      "created_at": "2026-03-24T10:30:00Z",
      "sent_at": "2026-03-24T10:30:01Z",
      "delivered_at": "2026-03-24T10:30:03Z"
    }
  ],
  "total": 150,
  "limit": 20,
  "offset": 0
}
GET/v1/messages/{id}

Get message details

Retrieve the full details of a single message by its ID, including carrier error information if the message failed.

Response

{
  "id": "msg_xxxxxxxxxxxx",
  "to": "+447911283461",
  "from": "+447700142857",
  "body": "Your appointment is confirmed for 2pm tomorrow.",
  "direction": "outbound",
  "status": "failed",
  "segments": 1,
  "cost": 4,
  "reference": "appt-reminder-12345",
  "created_at": "2026-03-24T10:30:00Z",
  "sent_at": "2026-03-24T10:30:01Z",
  "delivered_at": null,
  "error_code": "30006",
  "error_message": "Landline or unreachable carrier"
}

Numbers

GET/v1/numbers/available

Browse available numbers

Search the pool of available UK mobile numbers you can rent. Filter by area code, type, or a digit pattern.

monthly_cost is in pence (300 = £3.00/month).

Query parameters

ParameterTypeRequiredDescription
area_codestringNoFilter by UK area code (e.g. 020 for London, 0161 for Manchester)
typestringNomobile or geographic. Default: mobile
patternstringNoDigit pattern to search for (e.g. 7700)
limitintegerNoResults per page. Default: 20. Max: 100.
offsetintegerNoPagination offset

Response

{
  "numbers": [
    {
      "number": "+447700142857",
      "number_formatted": "+44 7700 142 857",
      "type": "mobile",
      "area": "London",
      "area_code": "020",
      "monthly_cost": 300,
      "currency": "GBP",
      "capabilities": ["sms_inbound", "sms_outbound"]
    }
  ],
  "total": 1250,
  "limit": 20,
  "offset": 0
}
POST/v1/numbers/rent

Rent a number

Provision a number from the available pool. The number is immediately usable for sending and receiving SMS after a successful response. Provisioning completes within 60 seconds.

Request body parameters

ParameterTypeRequiredDescription
numberstringYesThe E.164 number to rent, as returned by GET /v1/numbers/available
webhook_urlstringNoWebhook endpoint to receive inbound messages on this number
labelstringNoFriendly label for your own reference (e.g. Main business line)

Request body

{
  "number": "+447700142857",
  "webhook_url": "https://app.britishtext.com/webhooks/inbound",
  "label": "Main business line"
}

Response

{
  "id": "num_xxxxxxxxxxxx",
  "number": "+447700142857",
  "number_formatted": "+44 7700 142 857",
  "type": "mobile",
  "status": "active",
  "label": "Main business line",
  "webhook_url": "https://app.britishtext.com/webhooks/inbound",
  "monthly_cost": 300,
  "rented_at": "2026-03-24T10:30:00Z",
  "renews_at": "2026-04-24T10:30:00Z"
}
DELETE/v1/numbers/{id}

Release a number

Return a rented number to the available pool. The number enters a 72-hour cooldown before it can be rented again by anyone. Billing for the current month is not refunded.

Response

{
  "id": "num_xxxxxxxxxxxx",
  "number": "+447700142857",
  "status": "released",
  "released_at": "2026-03-24T15:00:00Z"
}
GET/v1/numbers

List rented numbers

Retrieve all numbers currently rented on your account, including usage statistics and renewal dates.

Query parameters

ParameterTypeRequiredDescription
statusstringNoactive or suspended. Default: all
typestringNomobile or geographic
limitintegerNoResults per page. Default: 20.
offsetintegerNoPagination offset

Response

{
  "numbers": [
    {
      "id": "num_xxxxxxxxxxxx",
      "number": "+447700142857",
      "number_formatted": "+44 7700 142 857",
      "type": "mobile",
      "status": "active",
      "label": "Main business line",
      "webhook_url": "https://app.britishtext.com/webhooks/inbound",
      "monthly_cost": 300,
      "rented_at": "2026-03-24T10:30:00Z",
      "renews_at": "2026-04-24T10:30:00Z",
      "messages_sent": 247,
      "messages_received": 89
    }
  ],
  "total": 2,
  "limit": 20,
  "offset": 0
}

Webhooks

BritishText pushes real-time events to your HTTPS endpoint via HTTP POST. Webhooks are the recommended way to receive inbound messages and delivery reports without polling. Your endpoint must return a 2xx response within 10 seconds. Failed deliveries are retried 3 times with exponential backoff (10s, 60s, 300s).

POST/v1/webhooks

Register webhook

Subscribe to one or more event types. Supply a shared secret to enable HMAC signature verification on incoming payloads.

Request body parameters

ParameterTypeRequiredDescription
urlstringYesYour HTTPS endpoint to receive events. Must be publicly reachable.
eventsarrayYesEvent types to subscribe to. See the event types table below.
secretstringNoShared secret used to compute the HMAC-SHA256 signature header

Request body

{
  "url": "https://app.example.com/webhooks/events",
  "events": ["message.received", "message.delivered", "message.failed"],
  "secret": "whsec_your_signing_secret"
}

Response

{
  "id": "wh_xxxxxxxxxxxx",
  "url": "https://app.example.com/webhooks/events",
  "events": ["message.received", "message.delivered", "message.failed"],
  "status": "active",
  "created_at": "2026-03-24T10:30:00Z"
}

Event types

EventTrigger
message.receivedInbound SMS received on a rented number
message.deliveredOutbound SMS confirmed delivered by carrier
message.failedOutbound SMS delivery failed
message.sentOutbound SMS accepted by carrier
number.suspendedRented number suspended due to spam/abuse
number.expiringRented number renewal due in 7 days

Inbound message payload (message.received)

{
  "event": "message.received",
  "timestamp": "2026-03-24T10:30:00Z",
  "data": {
    "id": "msg_xxxxxxxxxxxx",
    "from": "+447911283461",
    "to": "+447700142857",
    "body": "Yes, I'd like to book for 3pm.",
    "direction": "inbound",
    "received_at": "2026-03-24T10:30:00Z"
  }
}

Delivery report payload (message.delivered)

{
  "event": "message.delivered",
  "timestamp": "2026-03-24T10:30:03Z",
  "data": {
    "id": "msg_xxxxxxxxxxxx",
    "status": "delivered",
    "delivered_at": "2026-03-24T10:30:03Z",
    "reference": "appt-reminder-12345"
  }
}

Signature verification

Every webhook delivery includes the following headers. Use X-BritishText-Signature to verify the payload was not tampered with.

X-BritishText-Event: message.received
X-BritishText-Signature: sha256=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
X-BritishText-Timestamp: 1711270200
X-BritishText-Delivery-Id: del_xxxxxxxxxxxx

Verification algorithm

// Node.js example
const crypto = require("crypto");

function verifyWebhook(rawBody, timestamp, signature, secret) {
  const signed = crypto
    .createHmac("sha256", secret)
    .update(timestamp + "." + rawBody)
    .digest("hex");
  return `sha256=${signed}` === signature;
}

Reject payloads where the timestamp is more than 5 minutes old to prevent replay attacks.

Lookup

GET/v1/lookup/{number}

HLR number lookup

Perform a real-time Home Location Register (HLR) lookup on any phone number. Returns carrier, line type, porting status, and reachability. Useful for validating contacts before a campaign.

cost is in pence (1 = £0.01 per lookup). Rate limit: 10/second, 10,000/day.

Response

{
  "number": "+447911283461",
  "number_formatted": "+44 7911 283 461",
  "valid": true,
  "type": "mobile",
  "carrier": {
    "name": "EE",
    "mcc": "234",
    "mnc": "30"
  },
  "country": {
    "code": "GB",
    "name": "United Kingdom"
  },
  "ported": false,
  "reachable": true,
  "cost": 1
}

Account

GET/v1/account

Get account info

Retrieve your account details including current balance, usage statistics for today and this month, and your plan's rate limits.

balance is in pence (50000 = £500.00).

Response

{
  "sid": "AC_bt_xxxxxxxxxxxx",
  "name": "Acme Ltd",
  "status": "active",
  "balance": 50000,
  "currency": "GBP",
  "created_at": "2026-01-15T09:00:00Z",
  "usage": {
    "messages_sent_today": 1247,
    "messages_sent_month": 28450,
    "numbers_rented": 2,
    "lookups_today": 34
  },
  "rate_limit": {
    "messages_per_second": 50,
    "messages_per_day": 100000
  }
}
POST/v1/account/api-keys

Create API key

Create a new API key with an optional label. The auth token is returned only once in this response — store it securely. You can create separate keys per environment (production, staging, development) and revoke them independently.

The token is shown only once. Store it in a secrets manager immediately.

Request body parameters

ParameterTypeRequiredDescription
labelstringNoFriendly label for this key (e.g. Production, Staging)

Request body

{
  "label": "Production"
}

Response

{
  "id": "key_xxxxxxxxxxxx",
  "token": "at_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "label": "Production",
  "created_at": "2026-03-24T10:30:00Z"
}

Rate limits

Rate limits are applied per account. Every response includes the following headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 97
X-RateLimit-Reset: 1711270260

When rate limited (429), the response includes a Retry-After header indicating how many seconds to wait.

ResourceLimit
Send message (single)50/second, 100,000/day
Send message (bulk)10 requests/minute (each up to 1,000 messages)
API requests (general)100/second
Number lookup (HLR)10/second, 10,000/day

Error codes

All errors follow a consistent JSON structure. The code field is machine-readable; use it in your error handling logic.

{
  "error": {
    "code": "invalid_parameter",
    "message": "The 'to' field must be a valid E.164 phone number.",
    "param": "to"
  }
}
HTTPCodeDescription
400invalid_parameterA request parameter is missing or has an invalid value
401authentication_failedInvalid Account SID or Auth Token
402insufficient_balanceAccount balance too low to complete the operation
404number_not_foundNumber ID does not exist or does not belong to this account
409number_unavailableRequested number is no longer available for rent
422message_rejectedMessage rejected by carrier (spam filter, invalid content)
429rate_limit_exceededToo many requests — retry after the Retry-After header value
502carrier_errorUpstream carrier returned an error
500internal_errorUnexpected server error — contact support if it persists

Sandbox environment

Use sandbox credentials to test your integration without consuming credits or sending real messages. The sandbox simulates the full delivery lifecycle with a 2-second delay.

Sandbox Account SID prefix

AC_test_

Sandbox Auth Token prefix

at_test_

Magic test numbers

NumberBehaviour
+447700900000Always delivers successfully
+447700900001Always fails delivery
+447700900002Delivers after a 30-second delay
  • Messages are simulated — not delivered to real devices
  • Webhooks still fire with sandbox: true in the payload
  • Zero credits consumed in sandbox mode
  • Full delivery lifecycle simulated: queued → sent → delivered (2s delay)

Official SDKs

Official client libraries are in development. Each SDK will wrap the REST API with typed methods, automatic retry, webhook signature verification, and pagination helpers.

Node.js

@britishtext/sdk
npm · soon

Python

britishtext
PyPI · soon

PHP

britishtext/britishtext-php
Packagist · soon

Go

github.com/britishtext/britishtext-go
pkg.go.dev · soon

In the meantime, any HTTP client works with the REST API directly. See the quick start examples above.

Ready to start building?

Create a free account to get your API credentials. No credit card required for the 7-day trial.