1. Make a test key
Create an account if you haven't already, then in the dashboard go to Developers, API keys and create a key with the mode set to Test. Test keys start cc_test_. We only show a key once, so copy it somewhere safe, then put it in an environment variable:
export CAPTIFI_CONNECT_KEY="cc_test_..."2. Send a text
Post the number and the text to /messages. Numbers can be in any common UK format. The Idempotency-Key header is optional, but it means a retry of the same request can never send twice.
curl https://captificonnect.co.uk/api/v1/messages \
-H "Authorization: Bearer $CAPTIFI_CONNECT_KEY" \
-H "Idempotency-Key: quickstart-1" \
-H "Content-Type: application/json" \
-d '{ "to": "07412 000001", "body": "Hello from CaptiFi Connect" }'You get a 201 back with one entry per text. With a test key, test is true and nothing is charged. Anything we couldn't send to (a landline, a number outside the UK, someone who has opted out) is listed under rejected with a reason.
{
"data": {
"batch_id": "bat_01J9Z8X7W6V5T4S3R2Q1P0N9M7",
"messages": [
{
"id": "msg_01J9Z8X7W6V5T4S3R2Q1P0N9M8",
"status": "queued",
"to": "+447412000001",
"encoding": "gsm7",
"segments": 1,
"credits": 0,
"test": true
}
],
"rejected": []
},
"meta": { "credits": 0, "balance": 0, "replayed": false, "test": true }
}3. Check the status
Fetch the message to see where it's got to. A test text is marked sent after about a second and delivered a couple of seconds later. The response includes events, the full timeline.
curl https://captificonnect.co.uk/api/v1/messages/msg_01J9Z8X7W6V5T4S3R2Q1P0N9M8 \
-H "Authorization: Bearer $CAPTIFI_CONNECT_KEY"4. Get updates pushed to you
Polling works, but webhooks are better. Add an endpoint under Developers, Webhooks, pick the events you want, and we'll post each one to you as it happens, signed so you can check it came from us. Test texts fire webhooks too. The webhooks guide has the payloads and the signature check in three languages.
5. Go live
Once your account is approved and has credit, create a key with the mode set to Live (it starts cc_live_) and swap it in. Nothing else changes. Live sends use one credit per SMS part, and the response's meta.balance shows what's left.
Before you do, read errors so your code handles an empty balance (402) and the rate limit (429) gracefully, and see what test mode skips.
Node.js, Python and PHP
The same send in three languages. Each one reads the key from the environment and stops on an error.
// Node.js 18 or later (fetch is built in)
const res = await fetch('https://captificonnect.co.uk/api/v1/messages', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CAPTIFI_CONNECT_KEY}`,
'Idempotency-Key': 'order-881-ready',
'Content-Type': 'application/json',
},
body: JSON.stringify({ to: '07412 000001', body: 'Your order is ready to collect.' }),
});
const json = await res.json();
if (!res.ok) throw new Error(`${json.error.code}: ${json.error.message}`);
console.log(json.data.messages[0].id);# Python 3 with the requests package
import os, requests
res = requests.post(
"https://captificonnect.co.uk/api/v1/messages",
headers={
"Authorization": f"Bearer {os.environ['CAPTIFI_CONNECT_KEY']}",
"Idempotency-Key": "order-881-ready",
},
json={"to": "07412 000001", "body": "Your order is ready to collect."},
timeout=15,
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]["messages"][0]["id"])<?php
// PHP 8 with the curl extension
$ch = curl_init('https://captificonnect.co.uk/api/v1/messages');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CAPTIFI_CONNECT_KEY'),
'Idempotency-Key: order-881-ready',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['to' => '07412 000001', 'body' => 'Your order is ready to collect.']),
]);
$body = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($status >= 400) {
throw new RuntimeException($body['error']['code'] . ': ' . $body['error']['message']);
}
echo $body['data']['messages'][0]['id'];Every field and endpoint is in the API reference, and the same detail is in the OpenAPI document if you'd rather generate a client.