> ## Documentation Index
> Fetch the complete documentation index at: https://apidoc.bulkneo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Connect a number, create a key, and send your first WhatsApp message.

Five minutes, four steps. You need a BulkNeo account, a phone with WhatsApp on the number you want to send from, and something that can make an HTTP request.

<Steps>
  <Step title="Connect a number" icon="qrcode">
    Sign in to the portal and open **Instances**. Press **Create instance**, give the number a label you will recognise — `Sales`, `Support`, `Delivery` — and a QR code appears.

    On the phone that owns that WhatsApp number, open **WhatsApp → Settings → Linked devices → Link a device**, and scan the QR on screen.

    The status turns to **Connected** within a few seconds of a successful scan. The link stays active the same way WhatsApp Web does — you do not need to keep that page open.

    <Warning>
      Scan with the phone whose number you want to send from. Whatever number you scan is the number your customers will see the messages coming from.
    </Warning>
  </Step>

  <Step title="Create an API key" icon="key">
    Open the **API Keys** screen and create a key. Give it a label so you know later which server it lives on.

    <Warning>
      The key is shown **once**. Copy it straight into your server's environment variables or secret store. We keep only a hash of it, so nobody — including us — can show it to you again. If you lose it, revoke it and create another.
    </Warning>
  </Step>

  <Step title="Find your instance_id" icon="fingerprint">
    Every connected number has its own `instance_id`. It is shown next to the number on your **Instances** screen, in the **Instance ID** column, with a copy button.

    You can also list them from the API:

    ```bash theme={null}
    curl https://api.bulkneo.com/v1/instances \
      -H "apikey: YOUR_API_KEY"
    ```

    Each entry has an `instance_id`, your `label`, and `connected` — which tells you whether that number can send right now.
  </Step>

  <Step title="Send your first message" icon="paper-plane">
    Put your key in the `apikey` header, the `instance_id` of the number to send from, and the recipient in `to`.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.bulkneo.com/v1/messages/text \
        -H "apikey: YOUR_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "instance_id": "YOUR_INSTANCE_ID",
          "to": "919876543210",
          "text": "Hello from our API"
        }'
      ```

      ```javascript Node.js theme={null}
      const res = await fetch("https://api.bulkneo.com/v1/messages/text", {
        method: "POST",
        headers: {
          apikey: process.env.BULKNEO_API_KEY,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          instance_id: process.env.BULKNEO_INSTANCE_ID,
          to: "919876543210",
          text: "Hello from our API",
        }),
      });

      const body = await res.json();
      if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
      console.log(body.data.message_id);
      ```

      ```python Python theme={null}
      import os
      import requests

      res = requests.post(
          "https://api.bulkneo.com/v1/messages/text",
          headers={"apikey": os.environ["BULKNEO_API_KEY"]},
          json={
              "instance_id": os.environ["BULKNEO_INSTANCE_ID"],
              "to": "919876543210",
              "text": "Hello from our API",
          },
          timeout=30,
      )

      body = res.json()
      res.raise_for_status()
      print(body["data"]["message_id"])
      ```
    </CodeGroup>

    A success looks like this:

    ```json theme={null}
    {
      "success": true,
      "data": {
        "instance_id": "3f9c1a2b-7d4e-4c81-9f0a-2b6d5e8c1a34",
        "to": "919876543210",
        "type": "text",
        "status": "sent",
        "message_id": "3EB0C1D2F4A5B6C7D8E9",
        "provider_status": "PENDING"
      },
      "request_id": "b1f2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
    }
    ```

    Keep `data.message_id`. It is what you use later to [reply to](/guides/replies) or [react to](/api-reference/messages/reaction) that message.
  </Step>
</Steps>

## One key, many numbers

This is the one idea worth reading slowly, because every example on this site uses both fields and they do different jobs.

Your **API key** identifies your **account** — it is *who you are*.

Your **`instance_id`** identifies **one of your connected numbers** — it is *which of them the message goes out from*.

Picture a shop with three WhatsApp numbers: one for **Sales**, one for **Support**, one for **Delivery updates**. All three run on **one** key. Each request names the number it should leave from, so the order confirmation goes out from Sales and "your parcel is on its way" goes out from Delivery.

```
Sales      instance_id: "3f9c…"   ┐
Support    instance_id: "a1b7…"   ├─ one API key
Delivery   instance_id: "c8e2…"   ┘
```

No second key, no second account, nothing extra to set up.

<Check>
  Every number keeps its `instance_id` for life. It does **not** change when a number drops off and someone re-scans the QR — so there is nothing to redeploy after a reconnect. See [If your number disconnects](/guides/disconnects).
</Check>

## Formatting the recipient

`to` is the recipient's number with its country code and no leading zero:

| You have              | Send                              |
| --------------------- | --------------------------------- |
| `98765 43210` (India) | `919876543210`                    |
| `+91 98765-43210`     | `919876543210` or `+919876543210` |
| `098765 43210`        | `919876543210`                    |

Spaces, dashes, brackets and a leading `+` are accepted and stripped for you. What must remain is 6 to 15 digits. A number that fails that check comes back as `422 invalid_recipient`.

<Tip>
  Sending to numbers that are not on WhatsApp wastes your allowance and is one of the fastest ways to get a number restricted. [Check a list first](/guides/checking-numbers).
</Tip>

## Where to go next

<CardGroup cols={2}>
  <Card title="Send other message types" icon="paper-plane" href="/api-reference/introduction">
    Images, PDFs, locations, polls and more — twelve types, one pattern.
  </Card>

  <Card title="Handle errors properly" icon="triangle-exclamation" href="/errors">
    Which errors to retry, which to alert a human about.
  </Card>
</CardGroup>
