---
title: "Quickstart: send your first message"
description: "Get test credentials, send your first SMS with cURL, Node.js, Python or PHP, receive the delivery status, and check what to do before going live."
canonical: "https://omnichannels.ai/developers/quickstart/"
language: "en"
updated: "2026-10-10"
publisher: "BroadNet Technologies"
brand: "OmniChannels.ai"
section: "Get started"
---

# Quickstart: send your first message

Canonical: https://omnichannels.ai/developers/quickstart/
Language: en
Publisher: OmniChannels.ai by BroadNet Technologies

This guide takes you from test credentials to a delivered SMS on your own phone, then to a delivery status on your webhook. Every channel uses the same base URL and token, so the pattern you learn here carries over to WhatsApp, RCS and the rest.

## Before you start

You need three things:

- **An access token.** Test credentials are issued after a short access request (see step 1). There is no instant self-serve signup.
- **A verified test number.** Test sends go to your own verified numbers, so keep your phone nearby.
- **An HTTPS endpoint** for delivery statuses (optional for the first send). A tunnel such as ngrok works during development.

| Setting | Value |
| --- | --- |
| Base URL | `https://api.broadnet.me` (one base URL for test and production, no `/v1` prefix) |
| Auth header | `Authorization: Bearer $BROADNET_TOKEN` |
| Content type | `application/json` for single SMS; `multipart/form-data` for bulk and most channel sends |

## 1. Request test access

[Request test access](/demo/) and tell us your channels, destination countries, expected volumes and use case (for example OTP, alerts or marketing). An engineer reviews the request, issues your test credentials and verifies the numbers you will test with.

If you plan to resell messaging under your own brand, say so in the request. Resellers use the same API, and we set up the sub-account structure with you.

## 2. Store your token

Put the token in an environment variable. Every sample in these docs reads it from `BROADNET_TOKEN`.

```bash
export BROADNET_TOKEN="paste-your-token-here"
```

Keep the token on your servers only. See [Authentication](/developers/authentication/) for storage and rotation.

## 3. Send your first SMS

Call `POST /sms/sendSms` with four fields: `senderId`, `destinationNumber`, `message` and `messageType`. Write the destination as country code plus number, digits only, with no `+` or leading zeros.

```bash title="cURL"
curl -X POST https://api.broadnet.me/sms/sendSms \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "senderId": "OmniDemo",
    "destinationNumber": "447700900123",
    "message": "Your OmniDemo code is 482913",
    "messageType": "TEXT"
  }'
```

```js title="Node.js"
// Node.js 18+ (built-in fetch)
const res = await fetch("https://api.broadnet.me/sms/sendSms", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.BROADNET_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    senderId: "OmniDemo",
    destinationNumber: "447700900123",
    message: "Your OmniDemo code is 482913",
    messageType: "TEXT",
  }),
});

const messageId = await res.text(); // plain-text message ID
console.log(res.status, messageId);
```

```python title="Python"
import os
import requests

r = requests.post(
    "https://api.broadnet.me/sms/sendSms",
    headers={"Authorization": f"Bearer {os.environ['BROADNET_TOKEN']}"},
    json={
        "senderId": "OmniDemo",
        "destinationNumber": "447700900123",
        "message": "Your OmniDemo code is 482913",
        "messageType": "TEXT",
    },
    timeout=15,
)
print(r.status_code, r.text)  # r.text is the message ID
```

```php title="PHP"
<?php
$payload = json_encode([
    "senderId" => "OmniDemo",
    "destinationNumber" => "447700900123",
    "message" => "Your OmniDemo code is 482913",
    "messageType" => "TEXT",
]);

$ch = curl_init("https://api.broadnet.me/sms/sendSms");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 15,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("BROADNET_TOKEN"),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => $payload,
]);
$messageId = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

echo $status . " " . $messageId . PHP_EOL;
```

A successful call returns `200 OK`. The body is the message ID as plain text, with no JSON wrapper:

```text title="Response"
2603121407537573731
```

Save that ID next to your own record (an order, a login attempt). It is how you match delivery statuses later and how you avoid sending the same message twice.

> If the text contains Arabic, emoji or any character outside the GSM-7 alphabet, set `messageType` to `UNICODE`. The [SMS guide](/developers/sms/) explains encoding and segments.

## 4. Get the delivery status

Delivery statuses are pushed to the webhook URL configured on your account. A message moves through `SUBMITTED` and `SENT`, then ends as `DELIVERED` (or `READ` on channels that report reads), or as `FAILED` or `REJECTED`.

A minimal receiver stores the event and acknowledges straight away:

```js title="Node.js (Express)"
import express from "express";

const app = express();

app.post("/webhooks/omnichannels", express.json(), async (req, res) => {
  await saveStatusEvent(req.body); // your storage; process asynchronously
  res.sendStatus(200);             // acknowledge fast
});

app.listen(3000);
```

Give our team the public HTTPS URL of this endpoint so it can be set on your account. Payload fields vary by channel; the [Webhooks guide](/developers/webhooks/) shows how to handle them, deduplicate events and poll when you need to.

## 5. Go-live checklist

Production access is switched on after your sender identity, traffic purpose and sender IDs are approved. Approval runs in parallel with your integration work, and lead times depend on each country's regulator. Your code does not change: production uses the same base URL.

Before you switch, check that you have:

1. **Secured the token** in a secrets manager or environment variable, never in source control, mobile apps or browser code.
2. **Normalised numbers** to country code plus number, digits only.
3. **Chosen encodings** correctly (`TEXT` or `UNICODE`), or you call `POST /sms/identify` first.
4. **Stored every message ID** before treating a send as done.
5. **Handled errors by status code**: fix 4xx, retry network errors and 5xx with exponential backoff and jitter. See [Errors and limits](/developers/errors-and-limits/).
6. **Protected against duplicates.** The API takes no idempotency key, so record each send before you make it and check status after a timeout instead of resending blindly.
7. **Built an idempotent webhook handler** that answers with a 2xx quickly.
8. **Planned for rate limits**: back off on `429` and honour `Retry-After`.
9. **Registered sender IDs** for each destination country that requires them.
10. **Agreed throughput** with our team if you expect peaks, or if you need SMPP.

## Next steps

- [Authentication](/developers/authentication/): token handling, rotation and the 401 response.
- [SMS API](/developers/sms/): encoding, bulk sends, scheduling and number lookup.
- [WhatsApp API](/developers/whatsapp/): send approved templates and rich messages.
- [Webhooks](/developers/webhooks/): receive and process delivery statuses.
