Yeni Safe Mode yeni numaraları ısıtarak WhatsApp ban riskini azaltır. Detaylı bilgi →

Maytapi/Blog/Tutorials

WhatsApp API Getting Started: QR Code, First Message, Webhook

Connect a WhatsApp number by QR code or pairing code, send your first message with curl, receive replies on a webhook and keep the phone connected.

Tutorials Updated Oct 27, 2026·9 min read

WhatsApp API Getting Started: QR Code, First Message, Webhook

This guide takes you from an empty account to a working WhatsApp API integration in one sitting. You'll find your credentials, connect a phone with a QR code or a pairing code, send your first message with one curl call, receive replies on a webhook, and learn the few calls that keep the number connected. Every step is a plain HTTP request, so you can follow along in a terminal before you write any application code.

Maytapi is an unofficial WhatsApp API. You link your own WhatsApp number as a linked device, the same way WhatsApp Web works, and drive it over REST. There are no message templates, no Meta approval and no per-message fees. Because the number is a normal WhatsApp account, WhatsApp's usual spam rules apply to it, and the last part of this guide covers what that means in practice.

What you need before you start

  1. A Maytapi account. The free trial runs for three days and doesn't ask for a card. During the trial you can message up to 30 different numbers, so your first message can go to any number, including your own. The free Sandbox plan is limited to 5 recipient numbers.
  2. Your product ID and API token. Both are on the Product ID & Token page in the console (console.maytapi.com/settings/token). The product ID goes in the URL and the token goes in the x-maytapi-key header of every request.
  3. A phone with WhatsApp. Regular WhatsApp and WhatsApp Business both work. The phone needs the app installed and an internet connection while you link it.
  4. A terminal with curl. Later steps use Node.js for the webhook receiver.

Keep the credentials in environment variables so they never end up in your code or shell history files:

Terminal
export PRODUCT_ID="your-product-id"
export TOKEN="your-token"

All phone-level endpoints live under https://api.maytapi.com/api/PRODUCT_ID/PHONE_ID/. A few account-wide endpoints, such as listPhones and setWebhook, sit one level up at https://api.maytapi.com/api/PRODUCT_ID/. In this guide endpoints are written short, like GET /qrCode.

Getting started with the WhatsApp API in five steps: get the product ID and token, connect a phone by QR code or pairing code, send a first message, set the webhook and receive replies.

Step 1: Add a phone and find its phone ID

A "phone" in Maytapi is an instance that one WhatsApp number connects to. The simplest way to create one is the + Add New Phone button on the console's Phones page. Your trial or plan sets how many phones a product can have.

You can also add one from the API with POST /addPhone at product level. The body is optional. If you send a number, it's stored with the phone; otherwise the number is filled in when the phone connects:

Terminal
curl -X POST "https://api.maytapi.com/api/$PRODUCT_ID/addPhone" \
  -H "x-maytapi-key: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"number": "90532xxxxx67"}'

The response is the new phone record, and its id is your phone ID.

Note: If the product has already reached its phone limit, addPhone adds another paid phone to your subscription, which increases your bill. Check your plan's phone limit before you script it.

To see every phone on the product, call GET /listPhones:

Terminal
curl "https://api.maytapi.com/api/$PRODUCT_ID/listPhones" \
  -H "x-maytapi-key: $TOKEN"

Each item has an id (the phone ID), the number, a status and the phone's data, which includes its own webhook if one is set. Save the ID:

Terminal
export PHONE_ID="12345"

A new phone starts in qr-screen or idle. The status values you'll see are:

Status Meaning
loading The instance is starting or restoring a session
qr-screen Waiting for you to scan a QR code or enter a pairing code
active Connected and able to send and receive
idle Nobody linked a device in time, so the instance was parked. Requesting a QR code starts it again
conn-retry The connection dropped and is reconnecting
phone-error WhatsApp reports a problem on the phone side
disabled Turned off, for example when a subscription ends
logout The session was logged out, so the number has to be linked again
banned WhatsApp banned the number

Step 2: Connect the phone with a QR code

GET /qrCode returns the current QR code as a PNG image, not JSON. Save it to a file and open it:

Terminal
curl "https://api.maytapi.com/api/$PRODUCT_ID/$PHONE_ID/qrCode" \
  -H "x-maytapi-key: $TOKEN" \
  -o qr.png

If there's no QR code to show, for example because the phone is already connected, you get JSON instead with success: false and a message. If the phone was idle, the first request starts the instance and waits for it, so it can take a little longer than usual.

GET /screen also returns a PNG. On some connections it's a screenshot of the whole session screen, and on others it returns the QR code while the phone is waiting to be linked. Use qrCode when you only need the code to show to a user, and screen when you want to see what the session is doing.

Now scan it on the phone:

  1. Open WhatsApp on the phone you're connecting.
  2. Go to Settings (on iPhone) or the ⋮ menu (on Android) and tap Linked devices.
  3. Tap Link a device and scan the QR code.

QR codes rotate after a short time. If the scan fails, request qrCode again and scan the fresh one. The console shows the same code on the phone's QR Code tab and refreshes it for you.

Maytapi console Phones page with a phone in qr-screen status, the QR Code, Screen and Connect With Number tabs, and actions such as Redeploy, Factory Reset and Logout The Phones page: a new phone waits in qr-screen with its QR code, a pairing-code tab and the session actions.

Step 2 (alternative): Connect with a pairing code

If you can't show a QR code to the phone, for example when the user is setting it up remotely, link it with a pairing code instead. Send the WhatsApp number in international format, without + or spaces:

Terminal
curl -X POST "https://api.maytapi.com/api/$PRODUCT_ID/$PHONE_ID/connectWithPhoneNumber" \
  -H "x-maytapi-key: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"number": "90532xxxxx67"}'

The code comes back in connectionResult:

JSON
{ "success": true, "connectionResult": "A5GD36H" }

On the phone, open Linked devices, tap Link a device, choose Link with phone number instead and type the code. The phone has to be in qr-screen when you call this endpoint, and the number you send must be the one you're linking. The console offers the same flow on the Connect With Number tab.

QR code Pairing code
Endpoint GET /qrCode POST /connectWithPhoneNumber
Returns PNG image Code in connectionResult
On the phone Scan with the camera Type the code
Best for You can see the phone Remote or headless setup

Step 3: Check that the phone is connected

GET /status asks the live session for its state:

Terminal
curl "https://api.maytapi.com/api/$PRODUCT_ID/$PHONE_ID/status" \
  -H "x-maytapi-key: $TOKEN"

The response has success, the connected number, and a status object. The fields to check are loggedIn (true once the phone is linked), isQr (true while it waits for a scan) and loading:

JSON
{
  "success": true,
  "status": { "loggedIn": true, "isQr": false, "loading": false, "number": "90532xxxxx67" },
  "number": "90532xxxxx67"
}

The real response has more fields, but these three are enough for a "connected or not" check. On a phone that's idle, status answers with success: false and asks you to scan a phone first. For a quick check across all your numbers, the status field in listPhones should read active.

Step 4: Send your first message

With the phone active, send a text message. to_number is the recipient in international format with no +:

Terminal
curl -X POST "https://api.maytapi.com/api/$PRODUCT_ID/$PHONE_ID/sendMessage" \
  -H "x-maytapi-key: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"to_number": "90532xxxxx67", "type": "text", "message": "Hello from the Maytapi API!"}'

A successful call returns the chat it went to and an ID for the queued message:

JSON
{
  "success": true,
  "data": {
    "chatId": "90532xxxxx67@c.us",
    "msgId": "f3a9c2e0-4b7d-11ef-9a1c-0242ac120002"
  }
}

sendMessage puts the message in the phone's sending queue and answers right away. The message then leaves from your phone, and its delivery and read receipts arrive on your webhook as ack events. If nothing arrives, check the phone's status and the message logs in the console.

Images, documents, locations, polls, buttons and the other types use the same endpoint with a different type. They're all covered in how to send WhatsApp messages with the API.

Step 5: Receive messages on a webhook

Incoming messages, receipts and phone status changes are posted as JSON to a webhook URL. Set it once for the whole product with POST /setWebhook:

Terminal
curl -X POST "https://api.maytapi.com/api/$PRODUCT_ID/setWebhook" \
  -H "x-maytapi-key: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"webhook": "https://example.com/maytapi/webhook"}'

setWebhook posts a test text message to the URL to check it. If your server doesn't accept it, the call answers success: false with an error message, so start your receiver first. You can also paste the URL on the console's Developers > Webhook page. If one number should report to a different server, give that phone its own URL with POST /config. Phones without their own URL use the product webhook:

Terminal
curl -X POST "https://api.maytapi.com/api/$PRODUCT_ID/$PHONE_ID/config" \
  -H "x-maytapi-key: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"webhook": "https://client-a.example.com/webhook"}'

An incoming text message looks like this:

JSON
{
  "type": "message",
  "product_id": "your-product-id",
  "phone_id": "12345",
  "user": { "id": "90532xxxxx67@c.us", "name": "Customer", "phone": "90532xxxxx67" },
  "message": { "id": "3EB081AF26FADE6416D8", "type": "text", "text": "Hi!", "fromMe": false },
  "conversation": "90532xxxxx67@c.us",
  "receiver": "90532xxxxx21",
  "timestamp": 1574081887,
  "reply": "https://api.maytapi.com/api/your-product-id/12345/sendMessage"
}

conversation is the chat to answer in, and reply is the sendMessage URL for the phone that received the message. A minimal Express receiver answers 200 first and only then looks at the event. It also skips messages with fromMe: true, which are messages sent from your own number:

JavaScript
import express from "express";

const app = express();

app.post("/maytapi/webhook", express.json(), (req, res) => {
  res.sendStatus(200); // acknowledge first

  const event = req.body;
  if (event.type === "status") console.log("phone", event.phone_id, event.status);
  if (event.type !== "message" || event.message.fromMe) return;

  console.log(`${event.user.phone}: ${event.message.text}`);
});

app.listen(3000);

Anything slow, like a database write or an AI call, belongs after the response or on a job queue. While you develop locally, expose port 3000 with a tunnel such as cloudflared or ngrok and register the HTTPS URL it prints. Every event type, including acks, group events and calls, is described in the webhook events guide.

Step 6: Keep the phone connected

A linked device can be logged out from the phone, lose its connection or need a restart. Your webhook tells you when that happens with a status event:

JSON
{ "type": "status", "product_id": "your-product-id", "phone_id": 12345, "status": "qr-screen" }

The event is sent when the phone's status changes, and status is one of the values from the table in step 1, or logout when the session was logged out. Alert someone on qr-screen, idle, logout or phone-error, because the number can't send until it's linked again. A switch back to active means it's healthy.

Checklist for keeping a WhatsApp API phone connected: watch status webhooks, relink on qr-screen or logout, redeploy when stuck, factory reset only as a last resort, and warm up new numbers.

Three session calls cover most problems. All three are phone-level GET requests that return success and a short message:

Call What it does When to use it
GET /redeploy Restarts the phone's instance and keeps the session The phone seems stuck or stops responding
GET /logout Logs the number out and returns the phone to the QR screen You want to link a different number, or unlink this one
GET /factoryreset Recreates the instance, clears the stored session and number, and empties the phone's sending queue Nothing else helps
Terminal
curl "https://api.maytapi.com/api/$PRODUCT_ID/$PHONE_ID/redeploy" \
  -H "x-maytapi-key: $TOKEN"

Note: factoryreset wipes the WhatsApp session and drops messages still waiting in the queue. You'll have to scan a new QR code afterwards. Try redeploy first.

After a logout or a factory reset, connect again with step 2. The phone ID stays the same, so your code and webhook settings don't change.

Avoid bans. The number is a real WhatsApp account, and WhatsApp restricts accounts that look like spam. Replying to people who wrote to you first carries little risk. Sending to many new contacts in a burst carries a lot. Let a new number warm up for a few days before it sends anything proactive, and read how Safe Mode prevents WhatsApp bans. Before a campaign, check which numbers are on WhatsApp so you don't send to numbers that don't exist.

Next steps

You now have a connected number that sends messages and receives replies on your server. From here you can:

Published Oct 14, 2026 · Updated Oct 27, 2026 ← All posts
WhatsApp API'yi kullanmaya başlayın

Anahtarı alın, ilk mesajı on dakikada gönderin

Onay yok, şablon yok, kart yok. Üç gün boyunca tüm uçlar açık.