API Reference · v1

WapiSnap REST API

Send WhatsApp messages from any system over plain HTTP. Per-workspace API keys, JSON request/response, async send with status polling. Base URL:https://api.wapisnap.com.

Authentication

Every request to /v1/* must include an Authorization: Bearer header. Keys are scoped to a single workspace and are issued from Settings → API Keys in the dashboard. The plaintext value appears only at creation time; we store a bcrypt hash + the last 8 chars for display.

Authorization header
Authorization: Bearer wapi_live_a1B2c3D4e5F6g7H8i9J0kLmNoPqRsTuV
Treat API keys like passwords. Anyone holding the key can send messages from your workspace. Rotate by issuing a new key and revoking the old one — revocation is instant.

Every authenticated request lands in the workspace's request log, viewable at Settings → API Keys → View logs. Useful for confirming a call arrived as expected, debugging non-2xx responses, and correlating the request_id from an error response back to its origin.

Send a message

POST /v1/messages — enqueues a send and returns immediately with a message id. The actual Meta call happens out of band; poll GET /v1/messages/{id} for the final status. Two body shapes are supported.

Text message

Request
POST /v1/messages HTTP/1.1
Host: api.wapisnap.com
Authorization: Bearer wapi_live_...
Content-Type: application/json

{
  "to": "+919876543210",
  "type": "text",
  "text": "Your appointment is confirmed for tomorrow at 11 AM."
}

Template message

The template must be APPROVED on Meta's side. Variables follow the grouped shape: body, header, button_url. For templates containing a FLOW button, WapiSnap mints the flow_token server-side, you do not pass it.

Request
POST /v1/messages HTTP/1.1
Host: api.wapisnap.com
Authorization: Bearer wapi_live_...
Content-Type: application/json

{
  "to": "+919876543210",
  "type": "template",
  "template": {
    "name": "application_followup_new_lead",
    "language": "en",
    "variables": {
      "body": { "1": "Sam" }
    }
  }
}

Response

202 Accepted
HTTP/1.1 202 Accepted
Content-Type: application/json

{
  "id": "msg_cmqzr2pqj8009pyxcwhwz",
  "status": "queued",
  "to": "+919876543210",
  "type": "template",
  "conversation_id": "conv_cmqzr2pqj8009pyxcwh",
  "meta_message_id": null,
  "created_at": "2026-06-29T15:30:00.000Z"
}

Request body

FieldTypeDescription
to
Required
stringRecipient phone in E.164 format (e.g. +919876543210).
type
Required
"text" | "template"Message type. Determines which of the body fields below is read.
text
Conditional
stringRequired when type="text". 1–4096 chars.
template.name
Conditional
stringRequired when type="template". Must match an APPROVED template.
template.language
Conditional
stringLanguage code (e.g. en, en_US). Defaults to en.
template.variables
Optional
objectGrouped map. Keys: body, header, button_url. Each holds a positional 1-based map: { "1": "Sam" }.

Get message status

GET /v1/messages/{id} — returns the current status of a previously-sent message.

200 OK
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "msg_cmqzr2pqj8009pyxcwhwz",
  "status": "delivered",
  "to": "+919876543210",
  "type": "template",
  "conversation_id": "conv_cmqzr2pqj8009pyxcwh",
  "meta_message_id": "wamid.HBgMOTE5OTQ5MDIyODIzFQ...",
  "created_at": "2026-06-29T15:30:00.000Z",
  "delivered_at": "2026-06-29T15:30:02.450Z",
  "read_at": null
}

Status values

ValueMeaning
queuedAccepted by WapiSnap, not yet sent to Meta.
sentMeta acknowledged the send.
deliveredDelivered to the recipient handset.
readRead by the recipient.
failedSend failed; see the `error` field on the message.

Errors

Every error response carries the same envelope. request_id is the value to share with us when reporting an issue, it correlates to server-side logs.

401 Unauthorized
HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
  "error": {
    "code": "unauthorized",
    "message": "Invalid or revoked API key.",
    "type": "authentication_error",
    "request_id": "req_a1b2c3d4e5f6g7h8"
  }
}
400 Bad Request
HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": {
    "code": "invalid_request",
    "message": "Field 'to' must be in E.164 format (e.g. +919876543210).",
    "type": "validation_error",
    "param": "to",
    "request_id": "req_a1b2c3d4e5f6g7h8"
  }
}

Common codes

CodeHTTPMeaning
unauthorized401Missing, invalid, or revoked API key.
forbidden403The key is valid but lacks permission for this operation.
not_found404The referenced resource does not exist or belongs to a different workspace.
invalid_request400Payload failed validation; check the `param` field for the offending field.
rate_limited429Workspace exceeded the per-second cap. Honor the Retry-After header.
template_not_found404No approved template with that name + language exists in this workspace.
template_not_approved400The template exists but is in PENDING or REJECTED state.
no_wa_number400The workspace has no WhatsApp number configured.
contact_marketing_throttled409Smart-retry has temporarily blocked marketing sends to this contact (Meta 131049 protection).
internal_error500Server-side failure. The `request_id` lets us trace it in logs.

Rate limits

The default cap is 20 requests per second sustained, with bursts up to 30, per workspace. Requests beyond the burst budget receive 429 rate_limited with a Retry-After header in seconds. Need higher? Get in touch.

Versioning

The current version is v1, locked under the /v1 URL prefix. We will never make breaking changes to v1; additive fields (new optional request fields, new response fields) may land at any time. Future major versions will live alongside v1 under /v2 with at least 6 months of overlap.

Roadmap

  • v1.1 — Idempotency keys (client-supplied), outbound webhooks for status + inbound replies.
  • v1.2 — Media attachments (image, video, document, audio).
  • v1.3 — Dedicated POST /v1/flows/{id}/trigger for standalone flow sends.
  • v2.x — Conversation list / inbox read endpoints.