Appearance
REST API
Everything the dashboard does is API-first. Interactive OpenAPI reference: /docs on your API host (generated from the same zod schemas that validate requests).
Authentication
Authorization: Bearer wb_...Keys are org-scoped or app-scoped, with read / write / send / admin scopes. Rate limits are per org, in two lanes: transactional (POST /notifications, batches at one unit per recipient, Live Activity updates — 6,000/min by default) and standard (everything else — 1,200/min). Every authenticated /v1 response carries x-ratelimit-lane, x-ratelimit-limit, x-ratelimit-remaining and x-ratelimit-reset (seconds) for the lane it rode (a refused batch still reports what the lane has left — a refused charge is never counted), a refusal is a 429 with Retry-After, and GET /org/limits shows every allowance — the org-wide daily send cap and today's tally, both lanes' current windows, the per-IP ceiling above them, the batch size, the email allowance and events retention.
Route map (all under /v1)
| Area | Routes |
|---|---|
| Orgs | POST /orgs (admin bootstrap) · GET/PATCH /org · usage, invoice preview, audit log |
| Apps & credentials | apps CRUD · POST /apps/:id/credentials/{fcm,apns,twilio,whatsapp,telegram,rcs,line,zalo,viber,kakao} · settings (caps, quiet hours, webhook, email sender, eventsRetentionDays 7–90 or null for the platform's, emailTracking on/off for the open pixel and tracked links) |
| Suppressions | GET/POST/DELETE /apps/:id/suppressions — record and manage opt-outs (email, SMS, WhatsApp, Telegram, RCS, LINE, Zalo, Viber, KakaoTalk, voice); the worker's send gate honours them on every lane. Phone-number channels (SMS, voice, WhatsApp, RCS, KakaoTalk) share one identity: suppressing a number on any of them silences it on all of them, and DELETE via any of them clears the number |
| Twilio webhooks | POST /webhooks/twilio/sms-status and /voice-status (the platform-requested outcome callbacks, HMAC-signed under the tenant's auth token: late SMS failures become bounced, dead numbers are pruned, everything keyed on the signed device) · POST /webhooks/twilio/sms-inbound/:appId (point your Twilio number here; X-Twilio-Signature verified; STOP suppresses the phone identity, START lifts it) |
| WhatsApp webhook | GET/POST /webhooks/whatsapp/:appId — Meta Cloud API callbacks, authenticated by X-Hub-Signature-256 with the tenant's Meta app secret (fail-closed without it; GET is the verify-token handshake). read → attributed opened, post-acceptance failed → bounced (+device disable on 131026), inbound STOP replies → phone-identity suppression. Redeliveries deduped |
| Audience | subscribers (upsert on external id; PATCH /subscribers/:id {preferredChannels} — the channels marketing may use, null = any; honoured by campaigns, fallback and journeys, ignored by the transactional lane; also on /import/subscribers rows and in both exports), devices, tags, bulk import |
| Message templates | CRUD; templateName on POST /messages and POST /notifications (the latter renders {{ … }} at accept time from variables, the person's tags and language) |
| Response schemas | every core operation documents its 2xx body and its { error } 4xx bodies in /openapi.json, so generated clients get return types; timestamps are string/date-time, bodies always allow additional properties |
| Insights | funnels, cohort retention, RFM, event trends (GET /insights/event-trends?events=&days=&interval=), engagement heatmap (GET /insights/engagement-heatmap?days= — deliveries, opens and clicks by local day of week × hour), subscriber growth (GET /insights/subscriber-growth?days=&interval= — new subscribers per bucket with the running total), channel health (GET /insights/channel-health?days= — delivered / bounced / suppressed / failed and bounce rate per channel), delivery failures (GET /insights/delivery-failures?days=&limit= — sends that failed after every retry, by reason and lane, with whether a redrive has since landed them; the same open failures are failed in every campaign funnel) |
| Segments | CRUD + live preview counts |
| Messaging | messages (incl. localizations; delivery options badgeCount / sound / ttlSeconds / collapseKey / androidChannelId / priority mapped per channel — reserved key names on payload and on transactional data, other-typed values 400; payload.whatsapp = {templateName, languageCode, headerParams?, bodyParams?} references an approved Meta template — required on the base message and every A/B variant of a campaign with channels: ["whatsapp"], and on journey send-step messages targeting whatsapp; params Liquid-rendered per recipient) · campaigns (recurrence, tz, optimal-time, throttle, A/B) · POST /campaigns/:id/send · POST /campaigns/:id/cancel · POST /campaigns/:id/pause / resume (hold a multi-hour send mid-flight or a recurring campaign between occurrences; resume continues where it left off) · GET /campaigns/stats?ids= (live funnels for up to ten, the compare view) · GET /campaigns/export (every campaign with its rollup funnel as text/csv) |
| Transactional | POST /apps/:id/notifications — straight to the priority lane; variables render a template's (or inline) {{ … }} at accept time with the person's tags and language, strictly (an unresolved reference is a 400, never an empty message) · GET /apps/:id/notifications/:id — where a send stands (delivered / bounced / failed / suppressed / pending, per-device receipts; send or read scope) · POST /apps/:id/notifications/batch — same lane, up to 1,000 named recipients per call with shared content, per-recipient overrides, per-recipient results and idempotency keys derived from the batch key |
| Journeys | CRUD + PATCH {active} + stats |
| Live Activities | list · POST /live-activities/:id/{update,end} |
| Insights | funnel, cohorts, RFM |
| Integrations | catalog GET · per-type PUT/DELETE |
| Billing | GET /org/billing · POST /org/billing/checkout (Stripe-hosted) |
| White-label | POST/GET /org/clients · GET/PATCH /org/branding |
Public SDK endpoints (appId-scoped, no key)
GET /sdk/app/:appId · POST /sdk/subscriber · POST /sdk/register · POST /sdk/tags · POST /sdk/live-activities · in-app feed — these only let a client create/claim its own records within one app.
Ingest
POST /e on the ingest host: batched events with per-event validation (one malformed event never poisons a batch). Plus POST /i/segment/:appId for Segment inbound.
AI agents
@wingblaze/mcp-server exposes create_campaign, send_campaign, campaign_stats, send_transactional, org_usage, build_segment, create_segment and list_segments as MCP tools — point your agent at it and it can operate WingBlaze directly. Sending is two-phase on purpose: create_campaign returns a draft plus its live audience size, then send_campaign(campaignId) commits, so a retried tool call can never blast an audience twice.