Skip to content
Beta — the Waasl API is in private beta. Endpoints marked Coming soon are designed but not live yet. Request early access

Quickstart

This guide takes you from zero to a delivered WhatsApp message and a webhook on your server.

  1. Create an API key

    In the Waasl app open Settings → Developers → API keys and create a key. Pick the scopes you need — for this guide messages:write and contacts:read. The full key is shown once; store it in your secret manager.

    Terminal window
    export WAASL_API_KEY="wsl_test_your_key_here"
  2. Check the key

    Terminal window
    curl https://api.waasl.io/v1/me -H "Authorization: Bearer $WAASL_API_KEY"
    { "workspace_id": "ws_26N2SaWtMR", "workspace_name": "Diet Station", "environment": "test",
    "key_prefix": "wsl_test_yo", "scopes": ["messages:write", "contacts:read"] }
  3. Find your channel

    Terminal window
    curl https://api.waasl.io/v1/channels -H "Authorization: Bearer $WAASL_API_KEY"

    Note the id of your WhatsApp channel, e.g. ch_wa_7Yt2.

  4. Send a template message

    A new contact hasn’t written to you in the last 24 hours, so WhatsApp only accepts an approved template. Waasl creates the contact and conversation for you.

    Terminal window
    curl -X POST https://api.waasl.io/v1/messages \
    -H "Authorization: Bearer $WAASL_API_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: $(uuidgen)" \
    -d '{
    "channel_id": "ch_wa_7Yt2",
    "to": "+96550001234",
    "kind": "template",
    "template": { "name": "order_ready", "language": "ar", "params": ["سارة", "4821"] }
    }'

    The response is 201 with status: "queued". Sending is asynchronous — delivery updates arrive as webhooks.

  5. Receive webhooks

    Register an HTTPS endpoint for message events:

    Terminal window
    curl -X POST https://api.waasl.io/v1/webhook-endpoints \
    -H "Authorization: Bearer $WAASL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{ "url": "https://example.com/waasl/webhook", "events": ["message.received", "message.status_updated"] }'

    Save the secret from the response, then handle events — always verify the signature:

    import express from "express";
    import crypto from "node:crypto";
    const app = express();
    app.post("/waasl/webhook", express.raw({ type: "application/json" }), (req, res) => {
    const [t, v1] = req.header("Waasl-Signature").split(",").map((p) => p.split("=")[1]);
    const expected = crypto.createHmac("sha256", process.env.WAASL_WEBHOOK_SECRET)
    .update(`${t}.${req.body}`).digest("hex");
    if (!crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected))) return res.sendStatus(401);
    const event = JSON.parse(req.body);
    if (event.type === "message.status_updated") console.log(event.data.message.id, event.data.message.status);
    if (event.type === "message.received") console.log("New message:", event.data.message.body);
    res.sendStatus(200);
    });
    app.listen(3000);
  6. Reply inside the 24-hour window

    When the customer answers, the window is open and you can send free-form messages into the conversation:

    Terminal window
    curl -X POST https://api.waasl.io/v1/conversations/cv_3PzA91/messages \
    -H "Authorization: Bearer $WAASL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{ "kind": "text", "body": "شكراً سارة! طلبك بالطريق 🚚" }'