Skip to content
WhatsApp API
v1 · stable

Developer API

Send text and images through your connected WhatsApp instances, check connection state, and read your quota. Every request is authenticated, quota-checked, and metered automatically.

Base URL

https://wasapapi.codexlure.site/api/v1
Protocol
REST · JSON
Auth
apikey header
Endpoints
5
Rate limit
60 / 20 per min

This reference is public — read it before you sign up. API keys require an account on a plan that includes API access.

Create an account

Authentication

Every request is authenticated with an API key. Create one under API Keys and send it in the apikey header — an Authorization: Bearer header works too. Keys are secrets: keep them on your server and never ship them in browser or mobile code.

Request header
apikey: wa_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Base URL
https://wasapapi.codexlure.site/api/v1

Rate limits

Limits are counted per API key, per minute, and are separate from your monthly message quota. Exceeding one returns 429 with a Retry-After header.

60/min

Read requests

Instances, status, and usage endpoints.

20/min

Message sends

Text and image endpoints.

POST /messages/send

Send a text message

Deliver a plain text message through one of your connected instances. The recipient number is normalized automatically — country code is strongly recommended.

Body parameters

Field Type Required Description
instance string Required Instance name or ID, exactly as it appears in your dashboard.
number string Required Recipient phone number in international format, e.g. 60123456789. Max 20 characters.
message string Required Message body. Max 4096 characters.
typing boolean Optional Show the typing indicator before sending. Defaults to true. Ignored on Cloud API instances.
typing_delay_ms integer Optional How long the typing indicator stays visible, 0–5000 ms. Defaults to 1200.
curl -X POST https://wasapapi.codexlure.site/api/v1/messages/send \
  -H "apikey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "instance": "Sales",
    "number": "60123456789",
    "message": "Hello from our app!"
  }'
<?php

$payload = [
    'instance' => 'Sales',
    'number'   => '60123456789',
    'message'  => 'Hello from our app!',
];

$ch = curl_init('https://wasapapi.codexlure.site/api/v1/messages/send');

curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => json_encode($payload),
    CURLOPT_HTTPHEADER     => [
        'apikey: YOUR_API_KEY',
        'Content-Type: application/json',
    ],
    CURLOPT_RETURNTRANSFER => true,
]);

$response = json_decode(curl_exec($ch), true);
$status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
use Illuminate\Support\Facades\Http;

$response = Http::withHeaders([
    'apikey' => config('services.wasaas.key'),
])->post('https://wasapapi.codexlure.site/api/v1/messages/send', [
    'instance' => 'Sales',
    'number'   => '60123456789',
    'message'  => 'Hello from our app!',
]);

if ($response->created()) {
    $messageId = $response->json('id');
}
201 Created Response
{
    "message": "sent",
    "id": "3EB0C767D0C7C1F0A1B2",
    "to": "60123456789",
    "remaining": 19842
}
409 Conflict Response
{
    "message": "Instance is not connected."
}
429 Quota Response
{
    "message": "Monthly message quota exceeded."
}
POST /messages/send-image

Send an image

Send an image from a publicly reachable URL. Add a caption to deliver the image and text together — omit it for an image-only message.

Body parameters

Field Type Required Description
instance string Required Instance name or ID.
number string Required Recipient phone number in international format.
image_url string Required Public HTTPS URL of the image. Must be reachable from the internet. Max 2048 characters.
caption string Optional Text delivered together with the image. Max 4096 characters.
typing boolean Optional Show the typing indicator before sending. Defaults to true.
typing_delay_ms integer Optional Typing indicator duration, 0–5000 ms.
curl -X POST https://wasapapi.codexlure.site/api/v1/messages/send-image \
  -H "apikey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "instance": "Sales",
    "number": "60123456789",
    "image_url": "https://example.com/product.jpg",
    "caption": "New product launch — available today."
  }'
<?php

$payload = [
    'instance'  => 'Sales',
    'number'    => '60123456789',
    'image_url' => 'https://example.com/product.jpg',
    'caption'   => 'New product launch — available today.',
];

$ch = curl_init('https://wasapapi.codexlure.site/api/v1/messages/send-image');

curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => json_encode($payload),
    CURLOPT_HTTPHEADER     => [
        'apikey: YOUR_API_KEY',
        'Content-Type: application/json',
    ],
    CURLOPT_RETURNTRANSFER => true,
]);

$response = json_decode(curl_exec($ch), true);
$status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
use Illuminate\Support\Facades\Http;

$response = Http::withHeaders([
    'apikey' => config('services.wasaas.key'),
])->post('https://wasapapi.codexlure.site/api/v1/messages/send-image', [
    'instance'  => 'Sales',
    'number'    => '60123456789',
    'image_url' => 'https://example.com/product.jpg',
    'caption'   => 'New product launch — available today.',
]);
201 Created Response
{
    "message": "sent",
    "id": "3EB0C767D0C7C1F0A1B2",
    "to": "60123456789",
    "remaining": 19841
}
502 Failed Response
{
    "message": "Image could not be sent."
}
GET /instances

List instances

Return every WhatsApp instance on your account with its current connection status.

curl https://wasapapi.codexlure.site/api/v1/instances \
  -H "apikey: YOUR_API_KEY"
<?php

$ch = curl_init('https://wasapapi.codexlure.site/api/v1/instances');

curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER     => ['apikey: YOUR_API_KEY'],
    CURLOPT_RETURNTRANSFER => true,
]);

$instances = json_decode(curl_exec($ch), true)['data'] ?? [];
curl_close($ch);
use Illuminate\Support\Facades\Http;

$instances = Http::withHeaders([
    'apikey' => config('services.wasaas.key'),
])->get('https://wasapapi.codexlure.site/api/v1/instances')->json('data');
200 OK Response
{
    "data": [
        {
            "id": 12,
            "name": "Sales",
            "phone": "60123456789",
            "status": "connected",
            "created_at": "2026-07-01T08:14:22.000000Z"
        }
    ]
}
GET /instances/{name-or-id}/status

Check instance status

Query the live connection state straight from the WhatsApp engine. Returns connected, connecting, or disconnected.

curl https://wasapapi.codexlure.site/api/v1/instances/Sales/status \
  -H "apikey: YOUR_API_KEY"
<?php

$ch = curl_init('https://wasapapi.codexlure.site/api/v1/instances/Sales/status');

curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER     => ['apikey: YOUR_API_KEY'],
    CURLOPT_RETURNTRANSFER => true,
]);

$state = json_decode(curl_exec($ch), true);
curl_close($ch);
use Illuminate\Support\Facades\Http;

$state = Http::withHeaders([
    'apikey' => config('services.wasaas.key'),
])->get('https://wasapapi.codexlure.site/api/v1/instances/Sales/status')->json();
200 OK Response
{
    "instance": "Sales",
    "status": "connected"
}
404 Not found Response
{
    "message": "Instance not found."
}
GET /usage

Check usage & quota

Messages sent in the current billing period, your plan quota, any purchased top-up balance, and how much is left in total. remaining already includes topup_remaining.

curl https://wasapapi.codexlure.site/api/v1/usage \
  -H "apikey: YOUR_API_KEY"
<?php

$ch = curl_init('https://wasapapi.codexlure.site/api/v1/usage');

curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER     => ['apikey: YOUR_API_KEY'],
    CURLOPT_RETURNTRANSFER => true,
]);

$usage = json_decode(curl_exec($ch), true);
curl_close($ch);
use Illuminate\Support\Facades\Http;

$usage = Http::withHeaders([
    'apikey' => config('services.wasaas.key'),
])->get('https://wasapapi.codexlure.site/api/v1/usage')->json();
200 OK Response
{
    "period": "2026-07",
    "sent": 158,
    "quota": 20000,
    "topup_remaining": 5000,
    "remaining": 24842
}
GET /me

Test the connection

Confirm a key is valid and see which account it belongs to. Integration platforms call this when you connect an account.

curl https://wasapapi.codexlure.site/api/v1/me \
  -H "apikey: YOUR_API_KEY"
<?php

$ch = curl_init('https://wasapapi.codexlure.site/api/v1/me');

curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER     => ['apikey: YOUR_API_KEY'],
    CURLOPT_RETURNTRANSFER => true,
]);

$account = json_decode(curl_exec($ch), true);
curl_close($ch);
use Illuminate\Support\Facades\Http;

$account = Http::withHeaders([
    'apikey' => config('services.wasaas.key'),
])->get('https://wasapapi.codexlure.site/api/v1/me')->json();
200 OK Response
{
    "account": "Kedai Runcit Sdn Bhd",
    "email": "owner@example.com",
    "plan": "Growth",
    "features": {
        "webhooks": true,
        "scheduling": true,
        "ai": false
    },
    "instances": 2,
    "remaining": 24842
}
POST /hooks

Subscribe to events

Register a URL to receive events — the REST-hook pattern Zapier, Make and n8n use instead of polling. Subscribing twice to the same URL updates that subscription rather than creating a duplicate, so a re-enabled automation never doubles your events. Requires a plan with webhooks.

Body parameters

Field Type Required Description
url string Required HTTPS endpoint that will receive the POST. Max 2048 characters.
events array Required One or more of message.received, message.status, instance.status.
name string Optional Label shown in your dashboard. Defaults to API subscription.
curl -X POST https://wasapapi.codexlure.site/api/v1/hooks \
  -H "apikey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.zapier.com/hooks/catch/123/abc",
    "events": ["message.received"]
  }'
<?php

$ch = curl_init('https://wasapapi.codexlure.site/api/v1/hooks');

curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'apikey: YOUR_API_KEY',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        'url'    => 'https://example.com/wasap-hook',
        'events' => ['message.received'],
    ]),
    CURLOPT_RETURNTRANSFER => true,
]);

$hook = json_decode(curl_exec($ch), true);
curl_close($ch);
use Illuminate\Support\Facades\Http;

$hook = Http::withHeaders([
    'apikey' => config('services.wasaas.key'),
])->post('https://wasapapi.codexlure.site/api/v1/hooks', [
    'url'    => 'https://example.com/wasap-hook',
    'events' => ['message.received'],
])->json();
201 Created Response
{
    "id": 8,
    "url": "https://hooks.zapier.com/hooks/catch/123/abc",
    "events": ["message.received"],
    "secret": "whsec_9f2c…"
}
403 Forbidden Response
{
    "message": "Your plan does not include webhooks."
}
GET /hooks

List subscriptions

Every endpoint registered on the account, whether it was created here or in the dashboard. The signing secret is not repeated — it is only returned once, when the subscription is created.

curl https://wasapapi.codexlure.site/api/v1/hooks \
  -H "apikey: YOUR_API_KEY"
<?php

$ch = curl_init('https://wasapapi.codexlure.site/api/v1/hooks');

curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER     => ['apikey: YOUR_API_KEY'],
    CURLOPT_RETURNTRANSFER => true,
]);

$hooks = json_decode(curl_exec($ch), true)['data'] ?? [];
curl_close($ch);
use Illuminate\Support\Facades\Http;

$hooks = Http::withHeaders([
    'apikey' => config('services.wasaas.key'),
])->get('https://wasapapi.codexlure.site/api/v1/hooks')->json('data');
200 OK Response
{
    "data": [
        {
            "id": 8,
            "name": "API subscription",
            "url": "https://example.com/wasap-hook",
            "events": ["message.received"],
            "is_active": true,
            "last_delivered_at": "2026-07-21T09:40:11.000000Z",
            "created_at": "2026-07-20T04:02:55.000000Z"
        }
    ]
}
GET /hooks/sample

Fetch a sample event

The exact shape of an event, filled with example values. Integration builders use this to map fields without waiting for a real message to arrive.

Body parameters

Field Type Required Description
event string Optional Query parameter. Defaults to message.received.
curl "https://wasapapi.codexlure.site/api/v1/hooks/sample?event=message.received" \
  -H "apikey: YOUR_API_KEY"
<?php

$ch = curl_init('https://wasapapi.codexlure.site/api/v1/hooks/sample?event=message.received');

curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER     => ['apikey: YOUR_API_KEY'],
    CURLOPT_RETURNTRANSFER => true,
]);

$sample = json_decode(curl_exec($ch), true);
curl_close($ch);
use Illuminate\Support\Facades\Http;

$sample = Http::withHeaders([
    'apikey' => config('services.wasaas.key'),
])->get('https://wasapapi.codexlure.site/api/v1/hooks/sample', ['event' => 'message.received'])->json();
200 OK Response
{
    "event": "message.received",
    "created_at": "2026-07-21T10:15:30+00:00",
    "data": {
        "instance": "Sales",
        "from": "60123456789",
        "type": "text",
        "message": "Hi, is this still available?",
        "message_id": "3EB0F1A2C3D4E5F60718",
        "received_at": "2026-07-21T10:15:30+00:00"
    }
}
DELETE /hooks/{id}

Unsubscribe

Remove a subscription. Deliveries stop immediately.

curl -X DELETE https://wasapapi.codexlure.site/api/v1/hooks/8 \
  -H "apikey: YOUR_API_KEY"
<?php

$ch = curl_init('https://wasapapi.codexlure.site/api/v1/hooks/8');

curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['apikey: YOUR_API_KEY'],
    CURLOPT_RETURNTRANSFER => true,
]);

curl_exec($ch);
curl_close($ch);
use Illuminate\Support\Facades\Http;

Http::withHeaders([
    'apikey' => config('services.wasaas.key'),
])->delete('https://wasapapi.codexlure.site/api/v1/hooks/8');
200 OK Response
{
    "message": "unsubscribed"
}
404 Not Found Response
{
    "message": "Hook not found."
}

Webhooks

Instead of polling, register an endpoint and we push events to you as they happen. Add endpoints under Webhooks in your dashboard. Available on plans that include webhook access.

Events

EventFires when
message.received Someone sends a message to one of your connected numbers.
message.status An outbound message advances to sent, delivered, or read.
instance.status An instance connects or disconnects.
Verify the signature (PHP)
$raw       = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_WASAP_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_WASAP_SIGNATURE'] ?? '';

$expected = hash_hmac('sha256', $timestamp.'.'.$raw, WASAP_WEBHOOK_SECRET);

if (! hash_equals($expected, $signature)) {
    http_response_code(401);
    exit;
}

$event = json_decode($raw, true);
// $event['event'], $event['data'] ...

http_response_code(200);
message.received Body we POST
{
    "event": "message.received",
    "created_at": "2026-07-20T09:14:22+00:00",
    "data": {
        "instance": "Sales",
        "from": "60123456789",
        "type": "text",
        "message": "Ada stok saiz M?",
        "message_id": "3EB0C767D0C7C1F0",
        "received_at": "2026-07-20T09:14:22+00:00"
    }
}

Reply with any 2xx within 10 seconds. Non-2xx responses are retried three times (1m, 5m, 15m); after 10 consecutive failures the endpoint is paused and you are shown the reason in the dashboard. Every request carries X-Wasap-Event, X-Wasap-Timestamp, X-Wasap-Signature, and X-Wasap-Delivery.

Errors

Errors return the matching HTTP status with a JSON body containing a message field. Failed sends never consume quota.

Status Message What to do
401 Invalid or missing API key. The apikey header is absent, misspelled, or the key was revoked.
403 Account is inactive · No active subscription · Plan without API access. Reactivate the account, renew the subscription, or upgrade to a plan that includes API access.
404 Instance not found. No instance on your account matches that name or ID.
409 Instance is not connected. Scan the QR code again from the dashboard, then retry.
422 Validation failed. A required field is missing or a value is out of range. The response lists the offending fields.
429 Quota exceeded · Too many requests. The monthly message quota is used up, or you passed the per-minute rate limit.
502 Message could not be sent. The WhatsApp engine rejected the send. The attempt is logged as failed and does not consume quota.

Ready to build?

Create a key and send your first message in under five minutes.

Create an account