SHABAB WHATSAPPAPI DOCS · 1.3

API for SHABAB apps

One simple API. Every company has its own API key (starts with sbwa_, made in admin → Companies → New API key, shown once). Send it as Authorization: Bearer sbwa_…. Base address: https://wa.shababinfotech.com. All bodies are JSON (UTF-8).

1. Send a template (any time)

Use an approved template. Outside the 24-hour window only templates can be sent.

POST /api/v1/send
Authorization: Bearer sbwa_xxxxxxxx
Content-Type: application/json

{ "to": "96891234567", "template": "attendance_late_alert", "lang": "en",
  "params": ["Ahmed", "08:25 AM", "SHABAB INFOTECH"] }

Answer: {"ok":true,"id":"m3f…","wamid":"wamid.HBg…","status":"accepted","category":"utility"}. Keep id to check the status later.

Template with a PDF on top (template must have a DOCUMENT header): add "header": {"document": {"url": "https://…/payslip.pdf", "filename": "payslip.pdf"}}. OTP: {"to":"9689…","template":"otp_code","lang":"en","params":["482913"]} (the copy-code button is filled for you; the code is not kept in the log).

2. Send text, document or image (only within 24 hours)

Allowed only if this person wrote to the company's number in the last 24 hours. Else the answer is 422 with "window": false — send a template instead.

{ "to": "96891234567", "text": "Your order is ready. Thank you!" }
{ "to": "96891234567", "document": { "url": "https://…/invoice.pdf", "filename": "invoice.pdf", "caption": "Invoice SO-1024" } }
{ "to": "96891234567", "image": { "url": "https://…/photo.jpg", "caption": "New stock" } }

3. Upload a file first (optional)

POST /api/v1/media
{ "filename": "payslip.pdf", "mime": "application/pdf", "data": "<base64>" }
→ { "ok": true, "id": "1234567890" }      then use { "document": { "id": "1234567890", "filename": "payslip.pdf" } }

PDF, JPG, PNG, Office files, plain text. Max 15 MB.

4. Status of a message

GET /api/v1/status/m3f…      (our id or the wamid)
→ { "id": "m3f…", "status": "delivered", "category": "utility", "billable": true, "error": null, … }

Status goes queued → accepted → sent → delivered → read, or failed (with error).

5. Other calls

CallWhat
GET /api/v1/meCompany name, number, status.
GET /api/v1/templatesTemplates of the company with status (APPROVED / PENDING / REJECTED) and number of values.
POST /api/v1/read{"message_id":"wamid…"} — blue ticks for an incoming message.

6. Phone numbers

Give the number with country code, digits only: 96891234567. +968 9123 4567 and 0096891234567 also work. An 8-digit Oman number (91234567) gets the company's default country code (968).

7. Incoming messages to your app (callback)

SB sets a Callback URL (https) for the company in admin → Companies → Edit, and makes a callback secret. Each incoming message is sent as:

POST <your callback URL>
X-Shabab-Event: message
X-Shabab-Signature: sha256=<HMAC-SHA256 of the raw body with the callback secret, hex>

{ "event": "message", "company_id": 7,
  "message": { "id": "m…", "wamid": "wamid…", "from": "96891234567", "name": "Ahmed", "type": "text", "text": "Hello", "timestamp": "2026-10-13T08:00:00.000Z" } }

Check the signature (timing-safe compare) and answer 200 quickly.

8. Errors

CodeMeaning
400Something missing or wrong in the body (message says what).
401API key wrong or missing.
403Company disabled.
402PREPAID company: balance finished or no active pack. JSON has prepaid: true, error_en, error_ar. Nothing was sent; top up to continue (Call / WhatsApp +968 9732 9001).
409Company not ready (no WhatsApp token / number yet).
422Outside the 24-hour window, or template rejected.
429Too many requests (120 per minute per company).
502Meta refused it — the message starts with Meta: and says why.

9. Starter templates (EN + AR)

NameValues (params)
attendance_late_alertemployee name, time, company
daily_absent_summarydate, absent, late, company
payslip_readyemployee name, month, company
leave_statusemployee name, from, to, status, company
order_confirmedcustomer name, order no., total, shop
otp_code (authentication)code

10. Example (curl)

curl -X POST https://wa.shababinfotech.com/api/v1/send \
  -H "Authorization: Bearer sbwa_xxxxxxxx" -H "Content-Type: application/json" \
  -d '{"to":"96891234567","template":"payslip_ready","lang":"ar","params":["أحمد","سبتمبر 2026","شباب"]}'

11. Alert API for SHABAB's own apps (HQ META LEADS, NEXUS) — 1.2

Sends a WhatsApp message from SHABAB's own number (company #1) to SB or a staff phone, for example "new lead". Not for customers' companies. Token: the server's WA_NEXUS_TOKEN (same token NEXUS uses), sent as Authorization: Bearer ….

POST /api/nexus/alert
{ "to": "96897329001", "template": "new_lead_alert", "lang": "en", "vars": ["Ahmed", "Perfume POS", "+968 9xxx"] }
   or   { "to": "96897329001", "text": "New lead: Ahmed - Perfume POS" }

200 { "ok": true, "kind": "template", "id": "m…", "wamid": "wamid…", "status": "sent", "to": "9689••••700" }
400 missing / wrong "to", or neither template nor text   ·  401 token wrong   ·  405 not POST
422 "window closed – template needed"  (text only works inside 24 h after that phone wrote to SHABAB's number; a template always works)
429 too many alerts (30 per minute)   ·  502 Meta refused (message says why)

The alert log keeps only masked numbers. The NEXUS summary shows "alerts today".

12. Company API — 1.3 (keys made in the portal)

The company owner makes API keys in the portal: Portal → API & webhook → New key (shown once; only a hash is kept; keys can be revoked). The key works like the admin key: Authorization: Bearer sbwa_…. Limit: 120 requests per minute per company (then 429).

POST /api/v1/messages            same body as /api/v1/send: {"to","template","lang","params"} or {"to","text"} (text only inside 24 h)
POST /api/v1/contacts            { "phone": "96891234567", "name": "Fatma", "tags": ["customer"], "fields": {"city": "Muscat"},
                                   "order": {"no": "SO-1024", "status": "out_for_delivery", "total": "OMR 12.500"} }
                                 → { "ok": true, "contact": { phone, name, tags, fields, optedOut, windowOpen, lastIn, unread, assigned, isNew } }
                                 (fields order_no / order_status / order_total are saved; a follow-up rule "order_status = out_for_delivery" fires at once)
GET  /api/v1/contacts/96891234567   → the same contact object   (404 if unknown)
GET  /api/v1/conversations?since=2026-10-14T06:00:00Z&limit=100
                                 → { "conversations": [ { phone, name, lastAt, lastIn, unread, windowOpen, lastMessage: {dir, kind, text, status, at}, tags, assigned, needsHuman, optedOut } ] }
curl -X POST https://wa.shababinfotech.com/api/v1/messages -H "Authorization: Bearer sbwa_xxxxxxxx" -H "Content-Type: application/json" \
  -d '{"to":"96891234567","template":"order_confirmed","lang":"en","params":["Fatma","SO-1024","OMR 12.500","Estee Perfumes"]}'
curl -X POST https://wa.shababinfotech.com/api/v1/contacts -H "Authorization: Bearer sbwa_xxxxxxxx" -H "Content-Type: application/json" \
  -d '{"phone":"96891234567","name":"Fatma","order":{"no":"SO-1024","status":"out_for_delivery"}}'
curl "https://wa.shababinfotech.com/api/v1/conversations?since=2026-10-14T06:00:00Z" -H "Authorization: Bearer sbwa_xxxxxxxx"

13. Company webhook — 1.3

Set in the portal: API & webhook → Webhook (https address + secret shown once). We POST JSON with headers X-Shabab-Event, X-Shabab-Delivery (number), X-Shabab-Timestamp (unix seconds), X-Shabab-Signature: sha256=HMAC_SHA256(secret, raw body) and X-Shabab-Signature-V2: sha256=HMAC_SHA256(secret, timestamp + "." + raw body). Answer 2xx within 10 s; otherwise we retry after 1 min, 5 min, 15 min and 1 hour, then mark it failed (visible in the portal log).

{ "event": "message.received", "company_id": 7, "at": "2026-10-14T06:01:02.000Z",
  "message": { "id": "m…", "wamid": "wamid…", "from": "96891234567", "name": "Fatma", "type": "text", "text": "Is my order ready?", "media_id": null, "timestamp": "…", "new_contact": false } }
{ "event": "message.status", "message": { "id": "m…", "wamid": "…", "to": "96891234567", "status": "delivered" | "read" | "failed", "error": "", "template": "order_confirmed" } }
{ "event": "contact.stop" | "contact.start", "contact": { "phone": "96891234567" } }      { "event": "ping", "message": "Hello from SHABAB WHATSAPP 1.3.0" }

14. Website chat button — 1.3

Portal → Settings → Website chat button: switch ON, copy the one-line script and put it before </body> on the website. A floating WhatsApp button with a greeting appears; it opens wa.me (on Android the WhatsApp app). Colours follow the company theme; clicks are counted in the portal (Settings and Reports). If the website has a strict Content-Security-Policy, allow script-src https://wa.shababinfotech.com (the button sets its styles from the script, no inline styles needed).

<script src="https://wa.shababinfotech.com/widget.js?c=PUBLIC_ID" async></script>

SHABAB WHATSAPP 1.3 · SHABAB INFOTECH, Muscat.