Linking an instance
An instance is one WhatsApp number linked to Threadwire, the same way WhatsApp Web is linked to a phone. You can do all of this in your panel too; this page is for doing it through the API.
Add and link one
- Add it:
POST /v1/instanceswith aname(and, if you like, your ownexternal_ref). The answer has itsid: that is theinstance_idevery other request uses. - Show the QR code:
GET /v1/instances/{id}/qranswers JSON with the picture as a data URL:{"data": {"image": "data:image/png;base64,iVBOR…"}}. Putdata.imagein an<img src>as it is. The phone's owner scans it in WhatsApp → Settings → Linked devices. The code changes, so fetch it again every few seconds. If the codes ran out before anyone scanned one, fetching it starts a fresh session. - Wait for
working: the instance'sstatusbecomesworkinginGET /v1/instances/{id}, and aninstance.statuswebhook says so.
A code instead of a QR code: POST /v1/instances/{id}/pairing-code with the phone's number as phone. The person types the code in WhatsApp → Linked devices → Link a device → Link with phone number instead. At most 5 codes an hour per instance, counted together with your panel's "Link with a phone number instead" (then 429 with Retry-After).
What the answers mean while linking:
GET …/qranswers409while the instance is still starting (try again in a moment) and once it is linked.POST /v1/instancesanswers409withRetry-Afterwhile another instance of yours is being added (they are added one at a time), and, rarely,503withRetry-Afterwhile we add room for more instances. Try again after the wait.
An instance's status is starting, scan_qr, working, failed or stopped.
One WhatsApp number, one instance. A number that belongs to another instance is not linked a second time: the new link is logged out again, and link_refused on the instance says why and what to do. To move a number, link it on the instance that has it, or remove that instance first. This keeps each number's daily limits and warm-up its own. While link_refused is set, GET …/qr and the pairing code answer 409 with the same reason; POST /v1/instances/{id}/logout clears it and starts a new link. In the panel, the link window shows the reason and "Start a new link", which brings the QR code back.
Keep it running
POST /v1/instances/{id}/restartreconnects one that seems stuck. It stays linked.POST /v1/instances/{id}/stoptakes it offline on purpose (stopped: true); sends answer409until youstartit again.POST /v1/instances/{id}/startbrings it back.POST /v1/instances/{id}/logoutunlinks the phone, as removing a linked device in WhatsApp; the instance waits for a new QR code, from the same phone or another. Its id, settings, keys and messages stay; a new link starts warm-up again.DELETE /v1/instances/{id}removes it for good.
To protect the instance, restart, stop and logout answer 409 while WhatsApp is restricting it, and the four together are limited to 5 an hour per instance (429 with Retry-After). DELETE answers 409 only while a linked instance is under WhatsApp's temporary restriction or in the hour after WhatsApp refused a message; the answer says when it can be removed. An instance that is unlinked, disconnected or stopped can always be removed.
Settings
PATCH /v1/instances/{id} changes its name, reject_calls and protection_settings (see How sending protects your number). Send only what changes.
GET /v1/instances/{id} also shows chat_link, a wa.me link that opens a chat with it, and protection: where the instance stands today with its limits and safety score.
Its WhatsApp profile
GET /v1/instances/{id}/profile gives its name and picture_url (WhatsApp does not give the "about" text back). PATCH changes name (up to 25 characters), about (up to 139) or picture (a JPEG or PNG of at most 2 MB, by url or base64 data; null removes it). "WhatsApp profile" on the instance's page in your panel does the same. At most 10 changes a day per instance.
People report numbers without a name and picture more often, so set them before writing to anyone new.
Calls
WhatsApp calls to your instances arrive as call.received webhooks. Set reject_calls: true (PATCH /v1/instances/{id}, or "Settings" on the instance's page) to decline every call at once, or decline one with POST /v1/instances/{id}/calls/reject and the call's id (as call_id) and chat_id (as from). One-to-one calls only.
API keys
Make keys in your panel under Developers → API keys (admins only), one per system that calls the API, so each can be revoked on its own.
- Access: one of three.
- Full access may do everything.
- Send and read sends, and reads everything. That covers messages (edits, deletions, reactions and read marks too), broadcasts, OTPs, statuses, labels, number checks, declining a call, archiving a chat, and a group's name, settings and invite link. It may not manage an instance: add or remove one, link it (QR code or pairing code), change its settings, restart, stop, start or unlink it, or change its WhatsApp profile or AI agent. Nor may it create, join or leave a group, add or remove a group's people, or create or delete a channel.
- Read only reads instances, messages, chats, events, groups, channels, statuses, labels, broadcasts and OTPs. It sends and changes nothing. One contact's details, and a group's invite link, need a key that may send.
- One instance: a key can be made for one instance (from that instance's page, or "For" when you make a key). It reaches only that instance's messages, chats, groups, events and settings, as if your account had no others; it cannot add or remove instances (
403), and it stops working when its instance is removed. Give that instance its own webhook URL too, and the system behind it gets only its events. Use one per system that serves a single instance, and an account key for systems that use them all. - IP addresses: a key can be locked to your servers' addresses or ranges, so a leaked key is useless anywhere else.
A call beyond a key's access, or from another address, answers 403 with the reason.
Plans and limits
Sign up at /app/register for a 7-day free trial; no card needed. Before it ends, pay by card on your Billing page where offered, or by transfer and press "I've paid" there; otherwise the account pauses the day after, until you do. Nothing is charged automatically.
- Each account may make up to 600 requests a minute; past that,
429 Too Many RequestswithRetry-After. - A plan sets how many instances you may link (past that,
POST /v1/instancesanswers403). It may also set usage limits: messages a day, people messaged a month, API requests a month, number checks a day. Your Billing page shows the ones your plan has; where it has none, only each instance's protection limits you. Messages typed on the phone never count. Past a usage limit, the API answers429with the reason andRetry-After. - If your account is suspended, every request answers
403with the reason.