Skip to content
Threadwire Docs

Type to search every guide and API endpoint.

Get started

Quickstart

Send your first WhatsApp message through the Threadwire API in five steps: an account, a linked number, an API key, a request and a webhook.

Send your first WhatsApp message through the API, and receive the reply, in about five minutes. You need the phone with your WhatsApp number on it, and a second phone to write from.

Five steps

  1. Open an account

    Sign up at /app/register. The trial lasts 7 days, and needs no card.

  2. Link your WhatsApp number

    In your panel, click Add instance. On the phone, open WhatsApp, go to Settings → Linked devices → Link a device, and scan the QR code. When the instance shows as connected, copy its Instance ID from its page.

  3. Make an API key

    Open Developers → API keys → New key (admins only). Copy the key at once: it is shown only once. Keep it on your server, never in a web page or an app.

  4. Send yourself a message

    From your second phone, write "hi" to your number first: the instance's chat_link opens that chat. Then send to the second phone. YOUR_PHONE is its number in international format, like 201012345678: country code, no leading 0.

    curl https://threadwire.net/api/v1/messages \
      -H "Authorization: Bearer YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"instance_id": "YOUR_INSTANCE_ID", "to": "YOUR_PHONE", "text": "Hello from Threadwire"}'
    
    $request = curl_init('https://threadwire.net/api/v1/messages');
    curl_setopt_array($request, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => ['Authorization: Bearer YOUR_API_KEY', 'Content-Type: application/json', 'Accept: application/json'],
        CURLOPT_POSTFIELDS => json_encode(['instance_id' => 'YOUR_INSTANCE_ID', 'to' => 'YOUR_PHONE', 'text' => 'Hello from Threadwire']),
    ]);
    $message = json_decode(curl_exec($request), true)['data'];
    
    const response = await fetch('https://threadwire.net/api/v1/messages', {
      method: 'POST',
      headers: { Authorization: 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json', Accept: 'application/json' },
      body: JSON.stringify({ instance_id: 'YOUR_INSTANCE_ID', to: 'YOUR_PHONE', text: 'Hello from Threadwire' }),
    });
    const { data: message } = await response.json();
    
    import requests
    
    response = requests.post(
        'https://threadwire.net/api/v1/messages',
        headers={'Authorization': 'Bearer YOUR_API_KEY', 'Accept': 'application/json'},
        json={'instance_id': 'YOUR_INSTANCE_ID', 'to': 'YOUR_PHONE', 'text': 'Hello from Threadwire'},
    )
    message = response.json()['data']
    

    The answer comes at once, with the message queued:

    {"data": {"id": "01K…", "status": "queued", "phone": "201012345678", "body": "Hello from Threadwire"}}
    

    That phone wrote first, so this is a reply, and it arrives in seconds. Only one phone? Send to your instance's own number instead.

  5. Receive the reply

    Open Developers → Webhooks (admins only) and set your endpoint's URL. Now reply from the second phone. Your URL receives the reply as JSON:

    {"id": "evt_01K…", "type": "message.received", "created_at": "2026-10-01T10:00:00+00:00",
     "data": {"id": "01K…", "instance_id": "01K…", "phone": "201012345678", "body": "Hi!"}}
    

    Answer with any 2xx. No public URL yet? Fetch the same events with GET /v1/events.

Before you go live

  • Check every webhook's signature, so nobody else can post to your URL: a whole endpoint to copy.
  • Send an Idempotency-Key header with each message, such as an order number. A retry then returns the first message instead of sending a second: what to retry.
  • Handle a failed message. It becomes failed, with the reason in error: Waiting, errors and retries.
  • Turn on protection before writing to people who never wrote to you: PATCH /v1/instances/{id} with {"protection_settings": {"enabled": true}}. See How sending protects your number.
  • Give each system its own key, read-only where it only reads, and lock it to your servers' addresses: API keys.

Next