REST API v1 & v1-Session

Nuntio Developer Documentation

Send transactional and bulk SMS, manage contacts, run campaigns, and listen for delivery webhooks. Two auth modes: API keys for server-to-server and Sanctum bearer tokens for the dashboard.

Quick Start → Get an API key

Quick start

Nuntio has two surfaces, both base URL https://nuntio.africa/api:

All responses are JSON. All write endpoints (POST, PUT, DELETE) require Accept: application/json and Content-Type: application/json (or multipart/form-data for file uploads).

Test the API in 30 seconds

Copy this curl — it sends a single SMS via the public API. Replace YOUR_API_KEY and YOUR_API_SECRET with values from your dashboard.

curl -X POST https://nuntio.africa/api/v1/sms/send \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "to": "+255712345678",
    "message": "Hello from Nuntio!"
  }'

Authentication

1. Server-to-server — API key

Every /api/v1/* request must include your public key id and secret in two custom headers. The secret is verified against a bcrypt hash server-side; the key id alone is not enough.

X-API-Key: spk_live_xxxxxxxxxxxxxxxx
X-API-Secret: sps_live_xxxxxxxxxxxxxxxx

Generate keys from Dashboard → API Keys. The plain secret is shown exactly once at creation — store it in your secret manager immediately.

Required scope per endpoint

EndpointRequired scope
POST /v1/sms/send, /v1/sms/send-bulksms:send
GET /v1/sms/status/{external_id}sms:read
POST /v1/sms/estimatesms:read
GET /v1/pricingpricing:read
GET /v1/accountaccount:read

If your key lacks the required scope, the API returns 403 insufficient_scope.

2. Dashboard session — Sanctum bearer token

For browser sessions and the mobile app, log in with email and password. The response contains a long-lived bearer token; pass it as Authorization: Bearer … on every /api/* call (excluding the public auth endpoints).

POST https://nuntio.africa/api/auth/login
Content-Type: application/json

{
  "email": "you@example.com",
  "password": "your-password",
  "device_name": "my-laptop"
}
{
  "success": true,
  "message": "Welcome back, Jane!",
  "user": {
    "id": 1,
    "name": "Jane Doe",
    "email": "jane@example.com",
    "role": "user"
  },
  "token": "1|abc123def456..."
}

Then send:

curl https://nuntio.africa/api/contacts \
  -H "Authorization: Bearer 1|abc123def456..." \
  -H "Accept: application/json"

Errors & status codes

Every error response is JSON with this shape:

{
  "success": false,
  "error": "rate_limit_exceeded",
  "message": "API rate limit of 60 requests per minute exceeded."
}
error codeHTTPWhen
missing_credentials401X-API-Key or X-API-Secret header missing
invalid_credentials401Key/secret pair unknown, revoked, or expired
insufficient_scope403API key lacks the required scope for this route
account_inactive403Sanctum user account is deactivated
validation_error422Body failed Laravel validation (see errors field)
insufficient_balance402Wallet has no credits left
rate_limit_exceeded429Per-minute or per-IP quota exhausted
not_found404Resource id not found for this account
GATEWAY_ERROR422Payment gateway rejected the request
DEBIT_FAILED500SMS was sent but wallet debit failed (manual reconciliation)

Rate limits

Two layers:

Pagination

List endpoints return up to per_page items (default 20 or 25, max 100). Filter arguments are preserved across page changes — the response includes a pagination block.

{
  "success": true,
  "contacts": [ ... ],
  "pagination": {
    "current_page": 1,
    "last_page": 4,
    "per_page": 25,
    "total": 87
  }
}

v1 — Send a single SMS

API key
POSThttps://nuntio.africa/api/v1/sms/send

Body parameters

FieldTypeRequiredDescription
tostringYesRecipient phone, max 20 chars. E.164 recommended (e.g. +255712345678).
messagestringYesBody, max 1,600 chars. Long messages split into segments (153 chars per multi-part segment).
fromstringNoSender ID, max 11 chars. Defaults to your account's configured sender.
callback_urlstringNoURL that receives sms.sent / sms.delivered / sms.failed events for this message (JSON, same shape as webhook events, not signed). Must resolve to a public IP; redirects are not followed.

Response 200 OK

{
  "success": true,
  "message_id": 4231,
  "external_id": "01HXY...",
  "phone": "+255712345678",
  "network": "Vodacom",
  "segments": 1,
  "cost": 25,
  "status": "delivered"
}

On failure: HTTP 402 with the same shape and "success": false.

v1 — Send bulk SMS

API key
POSThttps://nuntio.africa/api/v1/sms/send-bulk

Send the same message to up to 1,000 recipients in a single call. Each recipient is a separate string in the to array.

{
  "to": ["+255712345678", "+255713456789", "+255714567890"],
  "message": "Reminder: Your appointment is tomorrow at 10am.",
  "from": "Clinic",
  "callback_url": "https://example.com/webhooks/sms"
}
{
  "success": true,
  "total": 3,
  "successful": 3,
  "failed": 0,
  "total_cost": 75,
  "messages": [
    { "phone": "+255712345678", "external_id": "01HX...", "success": true, "cost": 25, "segments": 1, "status": "delivered" },
    { "phone": "+255713456789", "external_id": "01HY...", "success": true, "cost": 25, "segments": 1, "status": "delivered" },
    { "phone": "+255714567890", "external_id": "01HZ...", "success": true, "cost": 25, "segments": 1, "status": "delivered" }
  ]
}

v1 — Check delivery status

API key
GEThttps://nuntio.africa/api/v1/sms/status/{external_id}

Look up a message by the external_id returned from /sms/send. The numeric message_id from the same response also works.

{
  "success": true,
  "message": {
    "external_id": "01HXY...",
    "phone": "+255712345678",
    "network": "Vodacom",
    "status": "delivered",
    "cost": 25,
    "segments": 1,
    "sent_at": "2026-08-10T10:23:00Z",
    "delivered_at": "2026-08-10T10:23:45Z"
  }
}

If the id doesn't exist or belongs to another account: HTTP 404 not_found.

v1 — Estimate cost

API key
POSThttps://nuntio.africa/api/v1/sms/estimate

Calculate segments, network, and cost for a message without sending it. Useful for live cost previews in the UI.

{
  "to": "+255712345678",
  "message": "Hello world"
}
{
  "success": true,
  "to": "+255712345678",
  "network": "Vodacom",
  "segments": 1,
  "characters": 11,
  "cost": 25,
  "currency": "TZS"
}

v1 — Get pricing tiers

API key
GEThttps://nuntio.africa/api/v1/pricing
{
  "success": true,
  "currency": "TZS",
  "base_rate": 25,
  "tiers": [
    {
      "id": 1,
      "tier_name": "Starter",
      "slug": "starter",
      "min_quantity": 100,
      "max_quantity": 999,
      "cost_per_sms": 25,
      "savings_percent": 0
    },
    {
      "id": 2,
      "tier_name": "Growth",
      "slug": "growth",
      "min_quantity": 1000,
      "max_quantity": 9999,
      "cost_per_sms": 23,
      "savings_percent": 8
    }
  ]
}

base_rate is the default per-SMS cost in SMSm credits (TZS) for volumes below the first tier.

v1 — Account info & credits

API key
GEThttps://nuntio.africa/api/v1/account
{
  "success": true,
  "account": {
    "name": "Jane Doe",
    "email": "jane@example.com",
    "company": "Acme Ltd",
    "country": "TZ"
  },
  "credits": {
    "remaining": 600,
    "currency": "TZS"
  }
}

Auth — Register

Public
POSThttps://nuntio.africa/api/auth/register

Create a new Nuntio account. Returns a Sanctum bearer token. Rate limited to 3 per IP per minute.

FieldTypeRequiredDescription
first_namestringYesMax 80 chars.
last_namestringYesMax 80 chars.
emailstringYesValid email, unique, max 160 chars.
phonestringYesMax 20 chars.
passwordstringYesMin 8 chars, mixed case, at least one number. Must be confirmed with password_confirmation.
companystringNoMax 160 chars.
countrystringNo2-letter ISO code, default TZ.
{
  "success": true,
  "message": "Account created successfully.",
  "user": { "id": 1, "name": "Jane Doe", "email": "jane@example.com" },
  "token": "2|xyz789..."
}

Auth — Login

Public
POSThttps://nuntio.africa/api/auth/login

Rate limited to 5 attempts per email+IP per minute.

FieldTypeRequiredDescription
emailstringYesEmail address.
passwordstringYesPlain password.
device_namestringNoLabel for this token (e.g. "work-laptop"). Max 120 chars.
rememberboolNoReserved.

Returns the same shape as /auth/register. On failure, returns 422 validation_error with {"errors":{"email":["Invalid email or password."]}}.

Auth — Logout

Sanctum
POSThttps://nuntio.africa/api/auth/logout

Revokes the bearer token used to make the request. Other tokens on the same account are not affected.

Auth — Current user

Sanctum
GEThttps://nuntio.africa/api/auth/me

Returns the authenticated user and wallet summary.

{
  "success": true,
  "user": { "id": 1, "name": "Jane Doe", "email": "jane@example.com", "role": "user", "two_factor_enabled": false },
  "wallet": { "sms_credits_remaining": 600, "lifetime_spend": 2500, "lifetime_topup": 20000 }
}

Dashboard

Sanctum
GEThttps://nuntio.africa/api/dashboard

Aggregated stats, charts, and recent activity for the dashboard home screen.

{
  "success": true,
  "stats": { "messages_sent": 1234, "delivered": 1180, "delivery_rate": 95.6, "credits_remaining": 600 },
  "charts": { "daily_volume": [...], "network_distribution": [...] },
  "recent": { "campaigns": [...], "messages": [...], "invoices": [...] }
}

Contacts

Sanctum

List contacts

GEThttps://nuntio.africa/api/contacts

Query parameters: q (search), status (active/inactive), opted_in (bool), group_id (int), per_page (default 25, max 100), page.

Create a contact

POSThttps://nuntio.africa/api/contacts
FieldTypeRequiredDescription
phonestringYesMax 20 chars. Must be unique per account.
first_name, last_namestringNoMax 80 chars each.
emailstringNoValid email.
companystringNoMax 160 chars.
city, region, countrystringNoFree text.
genderstringNoOne of male, female, other.
date_of_birthdateNoISO date.
is_opted_inboolNoDefault true. Required to receive SMS.
sourcestringNoProvenance tag, e.g. "csv_import".
custom_fieldsobjectNoFree-form key/value store.
group_idsint[]NoGroup ids to attach the contact to.

Show / update / delete

GEThttps://nuntio.africa/api/contacts/{id}
PUThttps://nuntio.africa/api/contacts/{id}
DELETEhttps://nuntio.africa/api/contacts/{id}

Update accepts the same fields as POST /contacts (all optional). Both PUT and DELETE are scoped to the authenticated user's contacts — passing another user's id returns 404 not_found.

Bulk import

POSThttps://nuntio.africa/api/contacts/bulk-import

Two accepted formats:

JSON body — up to 10,000 rows:

{
  "contacts": [
    { "phone": "+255712345678", "first_name": "Jane", "last_name": "Doe" },
    { "phone": "+255713456789", "email": "bob@example.com" }
  ],
  "skip_duplicates": true
}

Multipart CSV upload — first row must be the header, max 5 MB, up to 10,000 rows. Recognised headers (case-insensitive): first_name, last_name, phone, email, company. phone is required.

curl -X POST https://nuntio.africa/api/contacts/bulk-import \
  -H "Authorization: Bearer ..." \
  -F "csv=@/path/to/contacts.csv" \
  -F "skip_duplicates=true"

Response:

{
  "success": true,
  "imported": 487,
  "skipped": 12,
  "errors": []
}

Opt-out a contact

POSThttps://nuntio.africa/api/contacts/{id}/opt-out
{ "reason": "User requested via SMS" }

Sets is_opted_in = false, status = "opted_out", records timestamp and reason. The contact will be excluded from future campaigns and group sends.

Groups

Sanctum
GEThttps://nuntio.africa/api/groups
POSThttps://nuntio.africa/api/groups
PUThttps://nuntio.africa/api/groups/{id}
DELETEhttps://nuntio.africa/api/groups/{id}

Group payload: name (required, max 120), description (max 500), color (max 20), icon (max 50). The list endpoint returns each group with a contacts_count.

Templates

Sanctum
GEThttps://nuntio.africa/api/templates
POSThttps://nuntio.africa/api/templates
PUThttps://nuntio.africa/api/templates/{id}
DELETEhttps://nuntio.africa/api/templates/{id}

Template fields: name (required, max 120), category (max 80), content (required, max 1,600), variables (array of placeholder names), is_shared (bool — when true, the template is visible to all accounts on the same plan).

SMS history

Sanctum
GEThttps://nuntio.africa/api/sms/history

Query parameters: status (queued/sent/delivered/failed), phone (substring match), per_page (default 25, max 100).

Send (dashboard)

POSThttps://nuntio.africa/api/sms/send

Throttled to 30 sends per IP per minute. Same fields as the v1 endpoint, plus campaign_name (max 160) and schedule_at (ISO datetime in the future). callback_url must be SSRF-safe.

Cost preview (dashboard)

POSThttps://nuntio.africa/api/sms/preview

Returns segments, network, and per-recipient cost without sending.

Campaigns

Sanctum

List

GEThttps://nuntio.africa/api/campaigns

Query: status, per_page (default 20, max 100).

Create + send (or schedule)

POSThttps://nuntio.africa/api/campaigns
FieldTypeRequiredDescription
namestringYesMax 160.
messagestringYesMax 1,600.
typestringYessms, mms, or whatsapp.
sender_idstringNoMax 11 chars.
contact_idsint[]NoSpecific contact ids.
group_idsint[]NoGroup ids — all opted-in contacts in those groups are merged in.
template_idintNoTemplate whose usage_count will be incremented.
schedule_atdatetimeNoFuture ISO datetime. When set, the campaign is created with status scheduled.
callback_urlstringNoDelivery status URL.

Show / cancel / duplicate / delete

GEThttps://nuntio.africa/api/campaigns/{id}
POSThttps://nuntio.africa/api/campaigns/{id}/cancel
POSThttps://nuntio.africa/api/campaigns/{id}/duplicate
DELETEhttps://nuntio.africa/api/campaigns/{id}

Analytics

Sanctum

All endpoints accept a days parameter (default 30).

GEThttps://nuntio.africa/api/analytics/overview
GEThttps://nuntio.africa/api/analytics/daily?days=30
GEThttps://nuntio.africa/api/analytics/hourly?days=30
GEThttps://nuntio.africa/api/analytics/networks?days=30
GEThttps://nuntio.africa/api/analytics/top-campaigns?limit=10

Reports

Sanctum
GEThttps://nuntio.africa/api/reports
POSThttps://nuntio.africa/api/reports
GEThttps://nuntio.africa/api/reports/{id}/download
DELETEhttps://nuntio.africa/api/reports/{id}

Generate a PDF report. Fields: name, type (delivery / campaign / engagement / billing / network / compliance), date_from, date_to (after or equal to date_from), format (pdf), frequency (once / daily / weekly / monthly). Reports expire after 30 days.

API keys

Sanctum
GEThttps://nuntio.africa/api/api-keys

Lists all your keys. The hashed_secret is never returned. Each row shows secret_preview (last 4 chars), current scopes, rate_limit_per_minute, last-used timestamp and IP.

POSThttps://nuntio.africa/api/api-keys

Body: name (required, max 120), expires_at (optional). Returns the new key plus plain_secret — the secret is shown exactly once. Store it immediately.

{
  "success": true,
  "message": "API key created.",
  "api_key": { "id": 7, "key_id": "spk_live_abc...", "secret_preview": "wxyz", "scopes": ["sms:send","sms:read"], "rate_limit_per_minute": 60 },
  "plain_secret": "sps_live_this-is-shown-only-once-abc123def456..."
}
PUThttps://nuntio.africa/api/api-keys/{id}

Update name, scopes (array of strings), rate_limit_per_minute (1–10,000), or daily_limit (1+).

POSThttps://nuntio.africa/api/api-keys/{id}/revoke

Sets revoked_at. The key stops authenticating immediately but the row is preserved for audit.

DELETEhttps://nuntio.africa/api/api-keys/{id}

Permanently deletes the key. Revoke first if you need to keep the audit trail.

Webhooks (outgoing)

Sanctum

Nuntio can POST delivery status updates to a URL you control. Configure the URL and event subscriptions from the dashboard or the API below.

CRUD

GEThttps://nuntio.africa/api/webhooks
POSThttps://nuntio.africa/api/webhooks
PUThttps://nuntio.africa/api/webhooks/{id}
DELETEhttps://nuntio.africa/api/webhooks/{id}

Body: name, url (must be public http(s) — SSRF-protected), environment (production / sandbox), events (array, e.g. ["sms.delivered","sms.failed"]). On create, returns the webhook row plus plain_secret shown once.

Test a webhook

POSThttps://nuntio.africa/api/webhooks/{id}/test

Throttled to 5 per user+IP per minute. Sends a synthetic webhook.test payload to the registered URL and returns the delivery result (HTTP status, latency, error if any).

Payment methods

Sanctum
GEThttps://nuntio.africa/api/payment-methods
POSThttps://nuntio.africa/api/payment-methods
POSThttps://nuntio.africa/api/payment-methods/{id}/default
DELETEhttps://nuntio.africa/api/payment-methods/{id}

Fields: type (card / mpesa / tigopesa / bank / crypto), brand, last_four, exp_month, exp_year, phone (mobile money), bank_name, account_last4, token (gateway token — never returned in API responses), is_default. Setting a new default demotes the previous one in a single DB transaction.

Billing & wallet

Sanctum
GEThttps://nuntio.africa/api/billing/wallet

Returns lifetime spend, lifetime top-up, remaining credits, and the latest 20 wallet transactions.

PUThttps://nuntio.africa/api/billing/auto-recharge

Body: enabled (bool), threshold (TZS, ≥ 0), amount (TZS, ≥ 100). When enabled, the wallet auto-purchases amount SMSm credits when the credits drop below threshold..

GEThttps://nuntio.africa/api/billing/transactions

Query: per_page (default 25, max 100).

Pricing tiers & quotes

Sanctum
GEThttps://nuntio.africa/api/pricing-tiers
POSThttps://nuntio.africa/api/pricing-tiers/quote

Quote body: credits (int ≥ 1). Returns the matched tier, rate, subtotal, total, and savings vs. base rate.

{ "credits": 5000 }
{
  "success": true,
  "credits": 5000,
  "currency": "TZS",
  "rate_per_sms": 22,
  "subtotal": 110000,
  "total": 110000,
  "savings_vs_base": 15000,
  "tier": { "id": 2, "name": "Growth", "min_quantity": 1000, "max_quantity": 9999, "savings_percent": 12 }
}

Credit purchases

Sanctum

Initiate purchase (FastLipa USSD push)

POSThttps://nuntio.africa/api/credits/purchase
FieldTypeRequiredDescription
creditsintYes1 – 1,000,000.
phonestringYesMobile money phone (max 20 chars).
customer_namestringNoMax 100 chars. Defaults to the user's full name.

Returns the created CreditPurchase and a poll_url. The user approves the USSD prompt on their phone. On callback, the wallet is credited and the purchase is marked completed. If FastLipa is not configured, the response includes "configured": false and the purchase stays pending.

GEThttps://nuntio.africa/api/credits/purchases
GEThttps://nuntio.africa/api/credits/purchases/{id}

Polling this endpoint while the purchase is pending will also poll FastLipa for a fresh status and update the row accordingly.

POSThttps://nuntio.africa/api/credits/purchases/{id}/cancel

Only works on pending purchases. Returns 422 otherwise.

Invoices

Sanctum
GEThttps://nuntio.africa/api/invoices
GEThttps://nuntio.africa/api/invoices/{id}

Settings — Profile

Sanctum
PUThttps://nuntio.africa/api/settings/profile

Body: any of first_name, last_name, phone, company, job_title, bio, country, timezone, locale. Upload an avatar as avatar in multipart/form-data (image, max 2 MB).

Settings — Security

Sanctum
PUThttps://nuntio.africa/api/settings/security

Body: current_password (required), email (optional, must be unique), new_password (optional, must be confirmed, mixed case, ≥ 8 chars, ≥ 1 number). Changing the password revokes all other Sanctum tokens for the account.

Settings — Notification preferences

Sanctum
PUThttps://nuntio.africa/api/settings/notifications

Body: any of sms_verification_enabled, low_balance_alert, delivery_report, campaign_completion, marketing_emails.

Settings — Two-factor authentication

Sanctum
POSThttps://nuntio.africa/api/settings/2fa/toggle

Heads up. The 2FA toggle currently flips a flag on the user row but does not enroll a TOTP secret. Use a password manager and a strong unique password until a TOTP library is wired.

Settings — Delete account

Sanctum
DELETEhttps://nuntio.africa/api/settings/account

Body: password (required). Marks the account inactive, revokes all Sanctum tokens, then deletes the user row. The associated wallet, contacts, and messages are removed by cascade.

In-app notifications

Sanctum
GEThttps://nuntio.africa/api/notifications
POSThttps://nuntio.africa/api/notifications/{id}/read
POSThttps://nuntio.africa/api/notifications/read-all
DELETEhttps://nuntio.africa/api/notifications/{id}

Sender name requests

Sanctum

Request a custom alphanumeric Sender ID (e.g. MYSHOP) instead of the default. Reviewed manually by the Nuntio team.

GEThttps://nuntio.africa/api/sender-name-requests
POSThttps://nuntio.africa/api/sender-name-requests
GEThttps://nuntio.africa/api/sender-name-requests/{id}
POSThttps://nuntio.africa/api/sender-name-requests/{id}/cancel

Create body: sender_name (3–11 alphanumeric chars), sample_message (max 320), business_justification (max 500). Only one open (pending / under-review) request per account.

Outgoing webhook events

When a subscribed event fires, Nuntio POSTs a JSON payload to your URL. Every request is signed — see Signing & verifying below.

sms.sent

The message was accepted by the SMS network. Delivery confirmation follows as sms.delivered or sms.failed.

{
  "event": "sms.sent",
  "occurred_at": "2026-08-10T10:23:40Z",
  "data": {
    "external_id": "01HXY...",
    "phone": "255712345678",
    "network": "Vodacom",
    "status": "sent",
    "segments": 1,
    "cost": 25
  }
}

sms.delivered

{
  "event": "sms.delivered",
  "occurred_at": "2026-08-10T10:23:45Z",
  "data": {
    "external_id": "01HXY...",
    "phone": "+255712345678",
    "network": "Vodacom",
    "segments": 1,
    "cost": 25,
    "delivered_at": "2026-08-10T10:23:45Z"
  }
}

sms.failed

{
  "event": "sms.failed",
  "occurred_at": "2026-08-10T10:23:50Z",
  "data": {
    "external_id": "01HXY...",
    "phone": "+255712345678",
    "error_code": "DELIVERY_TIMEOUT",
    "error_message": "Provider did not confirm delivery within 60 seconds."
  }
}

Signing & verifying

Every outgoing webhook includes an X-Webhook-Signature header containing an HMAC-SHA256 of the raw request body, hex-encoded, computed with your webhook's signing secret. Verify server-side using constant-time comparison.

The plain webhook secret is shown exactly once when the webhook is created. If you lose it, you must delete the webhook and create a new one.

PHP

$rawBody = file_get_contents('php://input');
$expected = hash_hmac('sha256', $rawBody, $webhookSecret);
$provided = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';

if (!hash_equals($expected, $provided)) {
    http_response_code(401);
    exit;
}

$payload = json_decode($rawBody, true);
// ... process $payload['event'] / $payload['data']

Node.js

const crypto = require('crypto');

app.post('/webhooks/smspesa', (req, res) => {
  const raw = req.rawBody; // capture raw body in your middleware
  const expected = crypto
    .createHmac('sha256', process.env.SMSPESA_WEBHOOK_SECRET)
    .update(raw)
    .digest('hex');

  if (!crypto.timingSafeEqual(
        Buffer.from(expected),
        Buffer.from(req.headers['x-webhook-signature'] || '')
      )) {
    return res.status(401).send();
  }

  const { event, data } = JSON.parse(raw);
  // ... process
  res.status(200).send();
});

Python (Flask)

import hmac, hashlib
from flask import request, abort

@app.post('/webhooks/smspesa')
def handle():
    raw = request.get_data()
    expected = hmac.new(
        WEBHOOK_SECRET.encode(),
        raw,
        hashlib.sha256,
    ).hexdigest()
    if not hmac.compare_digest(expected, request.headers.get('X-Webhook-Signature', '')):
        abort(401)
    payload = request.get_json()
    # ... process payload['event'] / payload['data']
    return '', 200

SDKs & quick examples

PHP

// Install: composer require smspesa/smspesa-php
$client = new \SmsPesa\Client('YOUR_API_KEY', 'YOUR_API_SECRET');

$result = $client->send([
    'to'      => '+255712345678',
    'message' => 'Hello from Nuntio!',
]);
echo $result['external_id'];

JavaScript (Browser)

const res = await fetch('https://nuntio.africa/api/v1/sms/send', {
  method: 'POST',
  headers: {
    'X-API-Key': 'YOUR_API_KEY',
    'X-API-Secret': 'YOUR_API_SECRET',
    'Content-Type': 'application/json',
    'Accept': 'application/json',
  },
  body: JSON.stringify({
    to: '+255712345678',
    message: 'Hello from Nuntio!',
  }),
});
const json = await res.json();
console.log(json.external_id);

Python

import requests

res = requests.post(
    'https://nuntio.africa/api/v1/sms/send',
    headers={
        'X-API-Key': 'YOUR_API_KEY',
        'X-API-Secret': 'YOUR_API_SECRET',
        'Accept': 'application/json',
    },
    json={'to': '+255712345678', 'message': 'Hello!'},
)
print(res.json()['external_id'])

cURL

curl -X POST https://nuntio.africa/api/v1/sms/send \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"to":"+255712345678","message":"Hello from Nuntio!"}'

Need help? Email nuntio@nemotech.africa or chat with us in-app. We respond within an hour during business days.