API reference

Stepora has a small REST API that mirrors the Wati v3 API shape, so code written against Wati's v3 endpoints works against Stepora with the same paths and the same Bearer-token auth. It reads from and writes to your own Stepora account — never to Meta directly.

Base URL: https://stepora.xyz/api/ext/v3

1. Authentication — API keys

Every /api/ext/v3 call needs an API key in the Authorization header:

Authorization: Bearer sk_<your-key>

How to create one: in the panel, open Developers → API keys → New key. Give it a name and pick its scopes (below). The full key is shown once — copy it then. It is never shown again, never emailed, and never logged. If you lose it, rotate the key (below) and copy the new one.

Rotating a key

If a key leaks, rotate it instead of deleting it: in Developers → API keys, press Rotate next to the key (or call POST /api/developer/keys/:id/rotate from the panel session). Rotation keeps the key's name, scopes, owner, and expiry, generates a brand-new key, and the old key stops working immediately. The new key is returned once — copy it then. The key list shows rotated_at, the date and time of the last rotation, and the new key's prefix.

2. Scopes

Pick only the scopes your integration needs. A key with messages:read cannot send, and a key with messages:send cannot read contacts.

3. Read endpoints

These are live today.

GET /api/ext/v3

Index: API name, version, your client_id, and the exact list of covered and not-covered endpoints. Use it to check what this build supports before you code against it.

curl https://stepora.xyz/api/ext/v3 \
  -H "Authorization: Bearer sk_your_key_here"

GET /api/ext/v3/channels

Your WhatsApp channels (instances). Scope: messages:read. Secrets such as access tokens are never returned.

Example response:

{
  "data": [
    {
      "id": 1,
      "name": "Main store",
      "phone_number": "923001234567",
      "phone_number_id": "1234567890",
      "waba_id": "0987654321",
      "status": "connected",
      "provider": "whatsapp",
      "created_at": "2026-11-06 10:00:00"
    }
  ],
  "pagination": { "total": 1 }
}

GET /api/ext/v3/conversations

Your Team Inbox conversations, newest first. Scope: messages:read. Filter with ?status=open, assigned, resolved, or closed. Any other value returns invalid_status.

curl "https://stepora.xyz/api/ext/v3/conversations?status=open&limit=20" \
  -H "Authorization: Bearer sk_your_key_here"

Each conversation has id, contact_phone, contact_name, status, assigned_to, unread_count, last_message_at, and created_at.

GET /api/ext/v3/conversations/:id/messages

The messages of one conversation, oldest first. Scope: messages:read. A conversation that is not yours (or does not exist) returns conversation_not_found.

Each message has id, direction (in or out), body, type, wa_message_id, status, and created_at.

GET /api/ext/v3/templates

Your message templates. Scope: templates:read. Filter with ?status=draft, submitted, approved, or rejected, and ?category=marketing, utility, or authentication. Any other value returns invalid_status or invalid_category.

Each template has id, name, category, language, header (type and text), body, footer, buttons, status, and created_at. Only approved templates can be sent — see the send endpoint below.

GET /api/ext/v3/contacts

Your contacts. Scope: contacts:read. Search with ?search= (matches phone, name, or email) and filter with ?opt_in=0 or ?opt_in=1. Any other opt_in value returns invalid_opt_in.

curl "https://stepora.xyz/api/ext/v3/contacts?search=0300&opt_in=1&limit=20" \
  -H "Authorization: Bearer sk_your_key_here"

Each contact has id, phone, name, email, tags, opt_in, lead_score, intent, source, last_seen_at, and created_at.

4. Write endpoints — added in this build

These five endpoints were added in this build, alongside this page. They are the Wati v3 write surface: send a template, send a session message, send a file, download media, and update contact attributes. Each one checks the scope, the WhatsApp rules, and your wallet before it sends — a failed check returns an error and nothing is sent or charged.

POST /api/ext/v3/messages/template

Send an approved template message — the most-used endpoint, and the only way to start a conversation outside the 24-hour window. Scope: messages:send.

curl -X POST https://stepora.xyz/api/ext/v3/messages/template \
  -H "Authorization: Bearer sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "923001234567",
    "template_name": "order_confirmed",
    "parameters": ["Ayesha", "ORD-1042"],
    "broadcast_name": "order_confirmed"
  }'

POST /api/ext/v3/messages/session

Send a free-form session message. Scope: messages:send.

curl -X POST https://stepora.xyz/api/ext/v3/messages/session \
  -H "Authorization: Bearer sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"phone": "923001234567", "message": "Your order is on its way — it should reach you by tomorrow evening."}'

POST /api/ext/v3/messages/file

Send a file (image, video, document, or voice note) as a WhatsApp message. Scope: messages:send.

GET /api/ext/v3/media/:id

Download a media file attached to a message. Scope: messages:read.

PATCH /api/ext/v3/contacts/:id/attributes

Update a contact's custom attributes (for example city, language, or vip). Scope: contacts:write.

curl -X PATCH https://stepora.xyz/api/ext/v3/contacts/42/attributes \
  -H "Authorization: Bearer sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"attributes": {"city": "Lahore", "vip": true}}'

5. Rate limits

There is no separate per-key rate limit on /api/ext/v3 today — no call is throttled just for being an API call. The limits that do apply are the real ones:

If you send bursts, space template sends out and watch the status of each response — a failed send is never retried automatically.

6. Error codes

Errors are JSON: { "error": "code" }, sometimes with extra fields. The HTTP status is 400 for a bad request, 401 for a missing, wrong, or expired key, 403 for a scope or ownership problem, and 404 for a missing record.

7. Postman collection

Download the Postman collection — every endpoint above, ready to import.

8. Webhooks

Webhooks are managed in the panel (Developers → Webhooks), not over this API. Each webhook has a URL, a set of events (message.received, message.sent, message.session_sent, message.template_sent, message.read, order.confirmed, handover.started, contact.created, campaign.sent), and a secret that signs deliveries with HMAC-SHA256. The secret is shown once on creation and once on rotation. Failed deliveries are retried up to 5 times (5 minutes, then 1 hour, 6 hours, 12 hours) and can be retried by hand from the webhook's delivery log.

message.session_sent fires when a session (plain-text, inside the 24-hour window) message is sent; message.template_sent fires when a template message is sent (campaign sends and the POST /api/ext/v3/messages/template endpoint). The older generic message.sent event is kept for backwards compatibility but no send currently emits it — subscribe to the session/template events instead.

What the API cannot do

If an endpoint you need is missing, check GET /api/ext/v3 first — it lists exactly what is covered — then ask support.