# List Text Hooks

> Your Text Hooks, newest first.

`GET /v1/hooks`

Your Text Hooks, newest first.

Needs a key with the `messages:read` scope. [Keys and scopes](https://usebluebot.com/docs/concepts/api-keys)

## Query parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | integer | No | How many to return, 1 to 100. Default 25. 1 to 100. Default `25` |
| `cursor` | string | No | The `next_cursor` of the page before. Leave it out for the first page. Up to 200 characters |

## Example

```bash
curl "https://usebluebot.com/api/v1/hooks" \
  -H "Authorization: Bearer $BLUEBOT_API_KEY"
```

```ts
import BlueBot from '@usebluebot/sdk';

const client = new BlueBot({ apiKey: process.env.BLUEBOT_API_KEY });

const page = await client.hooks.list();
console.log(page.data);
```

```python
import os
from bluebot import BlueBot

client = BlueBot(api_key=os.environ["BLUEBOT_API_KEY"])

page = client.hooks.list()
print(page.data)
```

## Response

`200`: A page of Text Hooks.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `object` | "list" | Yes |   |
| `data` | array of TextHook | Yes |   |
| `data[].id` | string | Yes | A hook_ id. Starts with `hook_` |
| `data[].object` | "text_hook" | Yes |   |
| `data[].name` | string | Yes |   |
| `data[].url` | string | Yes | The address to post to. Anyone with it can send texts from your number, so keep it private. |
| `data[].enabled` | boolean | Yes |   |
| `data[].test_mode` | boolean | Yes | Posts are recorded and checked but no text is sent. |
| `data[].mapping` | object | Yes | How a post becomes a text. Each value is a template over the posted fields: `body` for the JSON or form, `query` for the address’s query string. |
| `data[].mapping.to` | string or null | Yes | Who to text, as a `{{body.…}}` path into the posted fields. Up to 200 characters |
| `data[].mapping.text` | string or null | Yes | The words, with `{{body.…}}` fields. Leave it empty to use `template_id`. Up to 2,000 characters |
| `data[].mapping.first_name` | string or null | Yes | Saved on the contact when it has no first name yet. Up to 200 characters |
| `data[].mapping.last_name` | string or null | Yes | Up to 200 characters |
| `data[].mapping.tags` | string or null | Yes | Tags to add, separated by commas. May use `{{body.…}}` fields. Up to 200 characters |
| `data[].template_id` | string or null | Yes |   |
| `data[].sequence_id` | string or null | Yes | A sequence each person is added to. Starts with `seq_` |
| `data[].last_used_at` | timestamp or null | Yes | When it last received a post. |
| `data[].created_at` | timestamp | Yes | When it was made. |
| `has_more` | boolean | Yes | Whether another page follows. |
| `next_cursor` | string or null | Yes | Send as `cursor` for the next page; null on the last. |

The answer, `200`:

```json
{
  "object": "list",
  "data": [
    {
      "id": "hook_1Hq2LxW9cVbN3mKpRtYs0a",
      "object": "text_hook",
      "name": "Calendly bookings",
      "url": "https://usebluebot.com/h/th_8Rk2mQ4zN7wX1cVbL5pT9yHsQ2aVc0Ld",
      "enabled": true,
      "test_mode": false,
      "mapping": {
        "to": "{{body.payload.questions_and_answers.0.answer}}",
        "text": "Hi {{body.payload.name}}, you’re booked for {{body.payload.scheduled_event.start_time}}. Text back if anything changes.",
        "first_name": "{{body.payload.first_name}}",
        "last_name": "{{body.payload.last_name}}",
        "tags": "calendly"
      },
      "template_id": null,
      "sequence_id": null,
      "last_used_at": "2026-11-13T18:02:00.000Z",
      "created_at": "2026-11-03T16:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

## Errors

Every refusal has the same envelope and a page of its own. These are the ones this operation can give.

| Code                                                    | Status | What it means                                                                                                                                    |
| ------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| [`unauthorized`](https://usebluebot.com/docs/errors/unauthorized)             | 401    | The request carried no key, or a key BlueBot doesn’t know: mistyped, revoked, or a test key sent to the live API.                                |
| [`insufficient_scope`](https://usebluebot.com/docs/errors/insufficient_scope) | 403    | The key doesn’t carry the scope the endpoint needs. Each endpoint’s reference names its scope.                                                   |
| [`rate_limited`](https://usebluebot.com/docs/errors/rate_limited)             | 429    | Too many requests. A key may make 120 requests a minute. The `RateLimit` header says how many are left, and `Retry-After` how long to wait.      |
| [`internal`](https://usebluebot.com/docs/errors/internal)                     | 500    | Something went wrong on BlueBot’s side. It was reported. Send the request again; with an Idempotency-Key that is always safe.                    |
| [`invalid_request`](https://usebluebot.com/docs/errors/invalid_request)       | 400    | Something in the request doesn’t fit: a missing or malformed field, a bad id, or a combination the endpoint refuses. `details` names each field. |

## Try it
