Your first integration
Getting started
Send a test message, check its delivery, and connect your first webhook. Once you have workspace access, the first sandbox send takes just a few minutes.
1. Get your sandbox key
- Follow your beta invitation to create your business workspace with your work email, then confirm your email address.
- Copy the sandbox key shown when you first sign in. It starts with
sg_test_and is shown only once. To create another, open API keys in the portal and select the correct project and sandbox environment.
# Replace the placeholder with your sandbox key. Keep it on your server.
export SWITCHGEAR_KEY='your_sandbox_api_key'2. Send your first message
Send a JSON request with your key in the Authorization header. Use a phone number in E.164 format, including the country code, such as +260971234567.
curl -i https://sandbox.switchgear.app/v1/messages \
-H "Authorization: Bearer $SWITCHGEAR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 7d0f3c2e-8a51-4b6e-9c1d-2f4a6b8c0e13" \
-d '{"channel": "sms", "to": "+260971234567", "body": "Your order A-17 is on its way."}'A successful send returns 202 Accepted and a message id. This example shows the relevant fields:
HTTP/1.1 202 Accepted
{
"id": "0199f7a2-5c1e-7b3d-9a40-6e2f1c8d4b57",
"channel": "sms",
"status": "queued"
}Copy the returned id into the command below to read the message and its events:
# Replace the placeholder with the id returned by your send request.
export SWITCHGEAR_MESSAGE_ID='your_message_id'
curl https://sandbox.switchgear.app/v1/messages/$SWITCHGEAR_MESSAGE_ID \
-H "Authorization: Bearer $SWITCHGEAR_KEY"In sandbox, read the simulated delivery from the test inbox. If the result is initially empty, repeat this query after delivery completes:
curl https://sandbox.switchgear.app/v1/sandbox/inbox/query \
-H "Authorization: Bearer $SWITCHGEAR_KEY" \
-H "Content-Type: application/json" \
-d '{"to": "+260971234567", "limit": 1}'Match the inbox result’s message_id to the id from your send response. You should see the message body. You can also use this endpoint to read one-time codes in automated tests.
3. Use the TypeScript SDK (optional)
@brivo/switchgear provides typed requests and responses, generates idempotency keys, and verifies webhooks. The package is currently private: request access through your Switchgear contact before using this example. You can use curl or any HTTP client without SDK access.
import { createClient } from '@brivo/switchgear';
const switchgear = createClient({
apiKey: process.env.SWITCHGEAR_KEY!,
baseUrl: 'https://sandbox.switchgear.app',
});
const since = new Date();
const message = await switchgear.messages.send({
channel: 'sms',
to: '+260971234567',
body: 'Your order A-17 is on its way.',
});
console.log(message.id, message.status); // "queued"
// Sandbox only: read what the simulator delivered, as the phone would have.
const delivered = await switchgear.sandbox.waitForMessage('+260971234567', { since });
console.log(delivered.body);4. Receive webhooks
Switchgear tells your server what happened (message.delivered, message.failed, otp.verified, verification.completed, inbound.received and more) by POSTing signed JSON to your webhook endpoints.
- In the portal, open Webhooks, add your HTTPS URL and choose the events. The signing secret (
whsec_…) is shown once: store it. - Verify
X-Switchgear-Signatureagainst the raw request body before processing the event. Return a 2xx response promptly; failed or timed-out deliveries are retried with backoff for up to 24 hours. - Deliveries can repeat, so skip an
event.idyou have already handled.
import express from 'express';
import { parseWebhook } from '@brivo/switchgear';
const app = express();
// Express: keep the raw body, the signature covers its exact bytes.
app.post('/switchgear', express.raw({ type: 'application/json' }), (req, res) => {
let event;
try {
event = parseWebhook(process.env.SWITCHGEAR_WEBHOOK_SECRET!, req.body.toString('utf8'), req.header('X-Switchgear-Signature'));
} catch {
return res.status(401).end();
}
// Deliveries can repeat: skip an event.id you have already handled.
// Example receipt only: persist or enqueue your work before acknowledging.
console.log(event.type, event.id);
res.status(204).end();
});
app.listen(3000);In your handler, persist the event or enqueue the work before acknowledging it. Use event.id to make processing safe when deliveries repeat.
Verify without the SDK · Node.js
If you use a different HTTP client, this helper verifies the signature with Node’s built-in crypto module. Pass it the endpoint secret, raw body, and signature header.
import { createHmac, timingSafeEqual } from 'node:crypto';
/** X-Switchgear-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>"> */
function verify(secret: string, rawBody: string, header: string | undefined, toleranceSeconds = 300): boolean {
const parts = Object.fromEntries((header ?? '').split(',').map((p) => p.split('=') as [string, string]));
const t = Number(parts.t);
if (!parts.v1 || !Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest();
const given = Buffer.from(parts.v1, 'hex');
return given.length === expected.length && timingSafeEqual(given, expected);
}5. Prepare for production
- Submit your business verification documents in the portal and request production access for your project. Approval and channel activation are required before sending live traffic.
- Top up your wallet; live sends are charged from it at the prices on the pricing page.
- For SMS with your own name as the sender, request a sender ID under Sender IDs; for WhatsApp, save your templates so they go to Meta for review.
- Use your production key (
sg_live_) withhttps://api.switchgear.app. Keep sandbox and production credentials separate; the request and response shapes stay the same.
Troubleshooting
Start with the HTTP status and the response’s error.code. Keep the X-Request-Id response header when contacting support.
- 401 · Authentication failed
- Check that
SWITCHGEAR_KEYis set, the bearer header is present, and the key is active and valid for the API host you’re calling. - 403 · Missing scope or restricted access
- Read
error.code. Forinsufficient_scope, check the key’s scopes; sending needsmessages:send, and status and inbox queries needmessages:read. The sandbox inbox requires a sandbox key. - 409 · Idempotency conflict
- A retry must use the original key and body within 24 hours. Use a new key for a new send or after the replay window has expired.
- 429 · Rate limited
- Follow
Retry-Afterwhen it is present and slow down requests. Check the API essentials for limits and batch behaviour. - The sandbox inbox is empty
- Delivery is asynchronous. Query again using the same destination and environment as your send. The TypeScript SDK’s
sandbox.waitForMessagepolls for you. - The message was accepted but failed later
- Read the message’s events to find the failure. The SMS simulator deliberately fails destinations ending in
00; the example number above uses the success path.
Explore individual endpoints or build an interactive service using the same workspace.