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

# Authentication

> Response URL tokens, API keys, and webhook signing secrets — what each one does.

There are three kinds of keys, and each one has its own job. Two prove who you are when you call us. One proves it is really us when we call you.

| Key                | Format             | Direction | Use it for                            |
| ------------------ | ------------------ | --------- | ------------------------------------- |
| Response URL token | Built into the URL | You → us  | Replying to the event you just got    |
| API key            | `mac_live_…`       | You → us  | Messaging any conversation, any time  |
| Webhook secret     | `whsec_…`          | Us → you  | Proving a request really came from us |

## Response URL token

Every event we send includes a `response_url`. The key is already part of the URL:

```text theme={null}
https://app.my-aichatbot.com/api/v1/responses/eyJ2IjoxLCJrIjoicmsxIi...
```

Do not send an `Authorization` header. Having the URL is your permission. This is why no-code tools are so easy here: map the field and POST to it.

<ParamField body="Time to live" type="45 minutes">
  The clock starts when the event is created. Expired tokens return `410 RESPONSE_URL_EXPIRED`.
</ParamField>

<ParamField body="Reuse" type="multi-use">
  Use it as many times as you like until it expires. Post several messages, or update one message many times.
</ParamField>

<ParamField body="Rate limit" type="30 requests / minute">
  Per token. Going over returns `429` with a `retry_after` value.
</ParamField>

<ParamField body="Scope" type="one conversation">
  The token only works for the conversation that created the event.
</ParamField>

The token is signed, so we can check it without a database lookup. Retries of the same event reuse the **same** token.

<Warning>
  Treat a `response_url` like a password. Anyone who has it can post into that conversation until it expires.
</Warning>

## API key

For anything outside the 45-minute window — cron jobs, long tasks, or messages you start yourself — use a key. Create one in your bot's settings.

```bash theme={null}
curl https://app.my-aichatbot.com/api/v1/conversations/{conversation_id}/messages \
  -H "Authorization: Bearer mac_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "text": "Your report is ready." }'
```

<ParamField header="Authorization" type="string" required>
  `Bearer mac_live_…`. Anything else returns `401 invalid_api_key`.
</ParamField>

How keys behave:

* **One key, one chatbot.** A key cannot touch another bot's conversations. Using it on the wrong bot's files endpoint returns `403 wrong_chatbot`.
* **Shown once.** We only store a hashed copy, plus the last few characters so you can tell keys apart. If you lose it, make a new one.
* **Can be turned off.** A revoked key stops working right away. You can also set a future end date, which gives you time to switch to a new key.
* **Rate limited** to 120 writes per minute and 300 reads per minute, per key.

<Warning>
  Keys belong on your server. Never put one in a browser, a mobile app, or a public repo. Anyone who has it can post as your bot.
</Warning>

## Webhook signing secret

This one works the other way around: we sign every request we send you, and you check the signature.

```text theme={null}
whsec_4f3a9b2c...   (whsec_ + 64 hex characters)
```

Find it in your bot's webhook settings. It signs the `X-MyAIChatbot-Signature` header on every POST we send, including retries and tests.

```text theme={null}
X-MyAIChatbot-Signature: v1=6e07b5c9...
```

Checking it is not optional. Without the check, anyone who learns your webhook URL can pretend to be us. Full guide in five languages: [Verifying signatures](/receiving-events/verifying-signatures).

<Note>
  A new secret starts working right away. There is no overlap period, so deploy the new secret first, then rotate.
</Note>

## Which one do I need?

<CardGroup cols={2}>
  <Card title="Replying to an event" icon="reply" href="/sending-messages/response-url">
    Use the `response_url`. No key needed.
  </Card>

  <Card title="Starting a message later" icon="key" href="/sending-messages/api-key">
    Use an API key. It never expires.
  </Card>
</CardGroup>
