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

# Quickstart

> Create your Comms workspace, mint a Messages API key, send your first text, and optionally wire a webhook.

Use this page the first time you connect Comms to your app or backend. You will open the dashboard, create a Messages API key, send a message, and optionally receive a webhook.

<Note>
  Keep `COMMS_API_KEY` on your server. Do not put Messages API keys in browser code, mobile apps, or public repositories.
</Note>

## Set up your workspace

<Steps>
  <Step title="Sign in to Comms">
    Go to [comms.osis.co/dashboard](https://comms.osis.co/dashboard) and sign in with your phone. That creates (or opens) the workspace that owns your line, keys, and inbox.
  </Step>

  <Step title="Open Messages API keys">
    In the product, open **[Messages API](https://comms.osis.co/dashboard/settings/api-keys)** — or use the **Create Messages key** control in the top bar.
  </Step>
</Steps>

## Create a Messages API key

For the quickest path, create a key with the default scopes: **Send messages** and **Read messages**. That is enough to send and list traffic on your line.

Building a long-running integration? Prefer a named key per environment (`Local development`, `Production worker`) so you can rotate without guessing.

<Steps>
  <Step title="Create a key">
    Click **Create key**. Name it something you will recognize later, like `Production backend` or `Staging worker`.
  </Step>

  <Step title="Choose what the key can do">
    Defaults cover most backends:

    | Scope            | Purpose                                                 |
    | ---------------- | ------------------------------------------------------- |
    | `comms_send`     | Outbound SMS / iMessage                                 |
    | `comms_read`     | List messages, conversations, contacts, delivery events |
    | `comms_webhooks` | Optional — register webhook URLs                        |

    Leave webhooks off until you need push. You can mint a second key later with only the scopes that job needs.
  </Step>

  <Step title="Copy the secret once">
    Store it in your environment as `COMMS_API_KEY`. The full value is only shown once — rotate if you lose it.

    ```bash theme={null}
    COMMS_API_KEY=osis_xxxxxxxxxxxxxxxxx
    ```
  </Step>
</Steps>

## Send your first message

Confirm the key works by sending a short text to a number you control.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://osis.co/api/v1/comms/messages" \
    -H "Authorization: Bearer $COMMS_API_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: demo-$(date +%s)" \
    -d '{
      "to": "+12125550147",
      "body": "Hello from Comms"
    }'
  ```

  ```typescript Node theme={null}
  const res = await fetch("https://osis.co/api/v1/comms/messages", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.COMMS_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": `demo-${Date.now()}`,
    },
    body: JSON.stringify({
      to: "+12125550147",
      body: "Hello from Comms",
    }),
  });

  console.log(res.status, await res.json());
  ```

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

  r = requests.post(
      "https://osis.co/api/v1/comms/messages",
      headers={
          "Authorization": f"Bearer {os.environ['COMMS_API_KEY']}",
          "Content-Type": "application/json",
          "Idempotency-Key": f"demo-{int(time.time())}",
      },
      json={"to": "+12125550147", "body": "Hello from Comms"},
  )
  print(r.status_code, r.json())
  ```
</CodeGroup>

A successful create returns **202** with a `message` object. Retries with the same `Idempotency-Key` return **200** and `"duplicate": true` without sending again.

<Tip>
  Always send an **Idempotency-Key** on outbound traffic. Retries, double-clicks, and queue redeliveries should never double-text a customer. See [Idempotency](/guides/idempotency).
</Tip>

## Read traffic back

```bash theme={null}
curl "https://osis.co/api/v1/comms/messages?limit=20" \
  -H "Authorization: Bearer $COMMS_API_KEY"
```

Requires `comms_read`. Filter with `conversation_id`, `since`, or `direction`.

## Optional: see a webhook

If you want push instead of poll:

<Steps>
  <Step title="Expose a local HTTPS endpoint">
    Add a `POST` route in your app and tunnel it with ngrok, Cloudflare Tunnel, or similar while developing.
  </Step>

  <Step title="Mint (or update) a key with webhooks">
    Ensure the key includes the `comms_webhooks` scope.
  </Step>

  <Step title="Register the URL">
    ```bash theme={null}
    curl -X POST "https://osis.co/api/v1/comms/webhooks" \
      -H "Authorization: Bearer $COMMS_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "url": "https://your-tunnel.example.com/hooks/comms",
        "events": ["message.received", "message.sent"]
      }'
    ```
  </Step>
</Steps>

Full guide: [Webhooks](/guides/webhooks).

## Next steps

<CardGroup cols={2}>
  <Card title="Send guide" href="/guides/send-your-first-message">
    Body fields, channels, and delivery behavior in depth.
  </Card>

  <Card title="API overview" href="/messages-api/overview">
    Base URL, errors, and the full endpoint map.
  </Card>

  <Card title="Authentication" href="/messages-api/authentication">
    Scopes, rotation, and what the key is (and is not).
  </Card>

  <Card title="Errors & rate limits" href="/guides/errors-and-rate-limits">
    Status codes, 429 handling, and retry advice.
  </Card>
</CardGroup>
