Blasty
REST API v1

API documentation

Send WhatsApp messages, run campaigns, and manage contacts and templates programmatically. Authenticate every request with a bearer token — create an account to get your keys.

Getting started

All requests go to the base URL below and authenticate with a bearer token.

Base URL

https://blasty.my/api/v1

Authentication header

Authorization: Bearer <your-api-key>

Example request

curl -X POST https://blasty.my/api/v1/messages/send \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"phone":"0123456789","body":"Hello from the API!"}'
Sending endpoints (messages/send, messages/bulk, campaigns) require a verified email on the key's owner. Each delivered message consumes one credit.

Connection

GET /api/v1/connection/status

Connection status

Report the WhatsApp connection state. For the wwebjs driver this lists each linked device; for the meta (Cloud API) driver it returns a single status.

GET /api/v1/connection/qr

Login QR code

Return a device login QR (data URL) for linking a WhatsApp account. Pass ?device=<id>; defaults to the resolved default device. Only available for the wwebjs driver.

Messages

GET /api/v1/messages

List messages

Paginated message log, newest first. Filter with ?status=, ?campaign_id=, and ?per_page= (default 25).

GET /api/v1/messages/{id}

Get message

Fetch the current status of a single message.

POST /api/v1/messages/send

Send a message

Queue a single message. Requires a verified email. Phone must parse as a Malaysian number. Optionally upsert a contact by passing save_contact or contact fields. Returns 202 Accepted.

Request body

{
  "phone": "0123456789",
  "body": "Hello from the API!",
  "name": "Ali",
  "external_id": "crm-42",
  "save_contact": true
}
POST /api/v1/messages/bulk

Send in bulk

Queue up to 1000 messages at once. Requires a verified email. Credits are charged up front for every valid recipient. Returns per-item queued and rejected arrays.

Request body

{
  "messages": [
    { "phone": "0123456789", "body": "Hi Ali" },
    { "phone": "0198887777", "body": "Hi Sara", "name": "Sara" }
  ]
}

Campaigns

GET /api/v1/campaigns

List campaigns

Paginated campaign log, newest first. Use ?per_page= to change page size.

GET /api/v1/campaigns/{id}

Get campaign

Fetch a single campaign with its template.

POST /api/v1/campaigns

Create campaign

Create and immediately dispatch a campaign. Requires a verified email. Provide recipients via contact_group_id, contact_ids, and/or inline recipients. Body comes from message_template_id or a free-text body.

Request body

{
  "name": "June promo",
  "body": "Salam {{name}}, here is your offer!",
  "contact_group_id": 3,
  "recipients": [
    { "phone": "0123456789", "name": "Ali" }
  ]
}

Contacts

GET /api/v1/contacts

List contacts

Paginated, searchable contact list. Filter with ?search= (name or phone) or ?external_id=.

POST /api/v1/contacts

Create / upsert contact

Create or update a contact. Idempotent on the normalized phone number — returns 201 on create, 200 on update.

Request body

{
  "phone": "0123456789",
  "name": "Ali",
  "external_id": "crm-42",
  "attributes": { "plan": "gold" }
}
GET /api/v1/contacts/{id}

Get contact

Fetch a single contact.

PUT /api/v1/contacts/{id}

Update contact

Update name, external_id, attributes, or opted_out.

DELETE /api/v1/contacts/{id}

Delete contact

Permanently delete a contact.

Templates

GET /api/v1/templates

List templates

Paginated template list. Pass ?active_only=1 to return only active templates.

POST /api/v1/templates

Create template

Create a reusable message template. A slug is generated from the name when omitted.

Request body

{
  "name": "Welcome",
  "body": "Salam {{name}}, welcome aboard!",
  "is_active": true
}
GET /api/v1/templates/{id}

Get template

Fetch a single template.

PUT /api/v1/templates/{id}

Update template

Update any template field.

DELETE /api/v1/templates/{id}

Delete template

Permanently delete a template.