YASend API

Quick start

Send your first WhatsApp message through the YASend API in about five minutes.

Base URL https://api.yasend.dev · Auth Authorization: Bearer <your API key> · Format JSON

1. Get an API key

Sign up at yasend.dev. Every account starts with a 24-hour free trial. Then, in the portal, open API keys and create a key. It starts with ysk_live_ and is shown only once: store it like a password, on your server only.

2. Create a session

A session is one WhatsApp number connected to YASend.

curl -X POST https://api.yasend.dev/v1/sessions \
  -H "Authorization: Bearer $YASEND_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "OTP sender"}'
const res = await fetch("https://api.yasend.dev/v1/sessions", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.YASEND_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({ name: "OTP sender" }),
});
const session = await res.json();
console.log(session.id);
import os, requests

r = requests.post("https://api.yasend.dev/v1/sessions",
                  headers={"Authorization": f"Bearer {os.environ['YASEND_KEY']}"},
                  json={"name": "OTP sender"})
session = r.json()
print(session["id"])
use Illuminate\Support\Facades\Http;

$session = Http::withToken(env('YASEND_KEY'))
    ->post('https://api.yasend.dev/v1/sessions', ['name' => 'OTP sender'])
    ->json();
echo $session['id'];
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
    new("Bearer", Environment.GetEnvironmentVariable("YASEND_KEY"));
var res = await http.PostAsJsonAsync("https://api.yasend.dev/v1/sessions", new { name = "OTP sender" });
var session = await res.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine(session.GetProperty("id"));

The response includes the session's own key in apiKey. That key only works for this one session, and it is also shown only once.

Start the session, then scan its QR code with the phone that owns the number: WhatsApp → Settings → Linked devices → Link a device.

curl -X POST https://api.yasend.dev/v1/sessions/$SESSION_ID/connect -H "Authorization: Bearer $YASEND_KEY"
curl "https://api.yasend.dev/v1/sessions/$SESSION_ID/qr?format=png" -H "Authorization: Bearer $YASEND_KEY" -o qr.png

The QR code refreshes about every 20 seconds, so fetch it again if it expires. Prefer typing a code? Use a pairing code instead.

When the phone is linked, GET /v1/sessions/{id} shows "status": "connected".

New numbers start slowly. To protect your number from being banned, a freshly linked number can send only a few messages a day at first, and needs a profile name, a profile photo and at least one manual conversation. See Safety & warm-up.

4. Send a message

curl -X POST https://api.yasend.dev/v1/messages \
  -H "Authorization: Bearer $YASEND_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sessionId": "'$SESSION_ID'", "to": "963912345678", "text": "Hello from YASend 👋"}'
const res = await fetch("https://api.yasend.dev/v1/messages", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.YASEND_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({ sessionId, to: "963912345678", text: "Hello from YASend 👋" }),
});
const message = await res.json();
if (!res.ok) throw new Error(`${message.error.code}: ${message.error.message}`);
console.log(message.status, message.waMessageId);
r = requests.post("https://api.yasend.dev/v1/messages",
                  headers={"Authorization": f"Bearer {os.environ['YASEND_KEY']}"},
                  json={"sessionId": session_id, "to": "963912345678", "text": "Hello from YASend 👋"})
r.raise_for_status()
print(r.json()["status"])
$message = Http::withToken(env('YASEND_KEY'))
    ->post('https://api.yasend.dev/v1/messages', [
        'sessionId' => $sessionId,
        'to' => '963912345678',
        'text' => 'Hello from YASend 👋',
    ])->throw()->json();
var res = await http.PostAsJsonAsync("https://api.yasend.dev/v1/messages",
    new { sessionId, to = "963912345678", text = "Hello from YASend 👋" });
res.EnsureSuccessStatusCode();

to is the phone number in international format, as digits only (no +, spaces or leading 00).

A plain send waits until WhatsApp has accepted the message, usually 3–10 seconds, because YASend paces messages like a human. To get an instant answer instead, add ?async=true and receive the result by webhook. See Sending messages.

Next steps