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

# List messages

> List your messages, inbound and outbound, newest first. Use it to catch up after your webhook endpoint was down, or to read a conversation's history.

Results are paginated: `has_more` tells you whether there is another page, and you get it by passing the `id` of the last message as `starting_after`. Pages are stable while new messages arrive: nothing is skipped or repeated. See [Pagination](/concepts/pagination).

Filters combine with AND. A filter value that matches nothing (including another account's `contact_id` or `chat_guid`) returns an empty page. An unknown or repeated query parameter returns `422 validation_error`.

Messages stay listed after their contact is deleted or blocked.

Lists allow 120 requests a minute per account, across all your API keys and all lists. Over that, the answer is `429 rate_limited` with a `Retry-After` header in seconds.

### List messages

**Method:** `GET` | **Endpoint:** `/v1/messages`

**Description:** List your messages, inbound and outbound, newest first. Use it to catch up after your webhook endpoint was down (see [Recover from downtime](https://docs.ibubbl.com/guides/webhook-retries.md#recover-from-downtime)), or to read a conversation's history.

**Authentication:** API key in the `Authorization` header: `Authorization: Bearer ib_pk_<64 hex>`. Create keys in the dashboard under **Settings → API access**.

#### Query parameters

All optional. Filters combine with AND.

| Parameter | Type | Description |
| - | - | - |
| `limit` | integer | How many messages to return, `1` to `100`. Defaults to `50`. Outside that range is `422 validation_error`, not rounded. |
| `starting_after` | string (UUID) | The `id` of the last message on the page you already have. Returns the messages after it. Leave it out for the first page. See [Pagination](https://docs.ibubbl.com/concepts/pagination.md). |
| `contact_id` | string (UUID) | Messages with this contact: the one-to-one conversation, plus group messages they sent or that were addressed to them as the group's primary contact. For one whole conversation, use `conversation_id`. |
| `conversation_id` | string (UUID) | Messages in this conversation, one-to-one or group. |
| `chat_guid` | string | Messages in the iMessage group with this `chat_guid`. It changes when someone is added to the group; the group's `conversation_id` doesn't. |
| `direction` | string | `inbound` (from contacts) or `outbound` (from your line, sent through the API, the dashboard or an automation). |
| `status` | string | One of `queued`, `pending`, `sent`, `delivered`, `read`, `failed`, `expired`, `cancelled`. |
| `created_after` | string (ISO 8601) | Messages with `created_at` strictly after this time. Include a time zone: `2026-11-10T09:30:00Z`. In a URL, write `Z`, or encode `+` as `%2B` (an unencoded `+` reads as a space and is rejected). |
| `created_before` | string (ISO 8601) | Messages with `created_at` strictly before this time. Same format. |

Any other query parameter, or one given twice, returns `422 validation_error` naming it. A misspelt `startingAfter` is refused instead of quietly returning the first page again.

A filter that matches nothing returns an empty page, including a `contact_id`, `conversation_id` or `chat_guid` from another account. Messages stay listed after their contact is deleted or blocked.

**Rate limit:** 120 list requests per 60 seconds per account, across all your API keys and all list endpoints. Over that, you get `429 rate_limited` with a `Retry-After` header; see [Rate limits](https://docs.ibubbl.com/concepts/limits.md#rate-limits).

```bash cURL theme={null}
# Sent as ?limit=50&created_after=2026-11-10T09%3A30%3A00Z
curl -G https://api.ibubbl.com/v1/messages \
  -H "Authorization: Bearer $IBUBBL_API_KEY" \
  --data-urlencode "limit=50" \
  --data-urlencode "created_after=2026-11-10T09:30:00Z"

# Next page: add the id of the last message you received.
#   --data-urlencode "starting_after=8b3a4e72-1c2d-4e5f-9a0b-2c3d4e5f6a7b"
```

```typescript TypeScript theme={null}
const params = new URLSearchParams({
  limit: "50",
  created_after: "2026-11-10T09:30:00Z",
});

const res = await fetch(`https://api.ibubbl.com/v1/messages?${params}`, {
  headers: { Authorization: `Bearer ${process.env.IBUBBL_API_KEY}` },
  signal: AbortSignal.timeout(10_000),
});

const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.detail?.error}`);
for (const message of data.data) {
  console.log(message.created_at, message.direction, message.status, message.body);
}
// More? Repeat with starting_after = data.data[data.data.length - 1].id
console.log("has_more:", data.has_more);
```

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

import requests

API_KEY = os.environ["IBUBBL_API_KEY"]

res = requests.get(
    "https://api.ibubbl.com/v1/messages",
    headers={"Authorization": f"Bearer {API_KEY}"},
    params={"limit": 50, "created_after": "2026-11-10T09:30:00Z"},
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['detail']['error']}")
for message in data["data"]:
    print(message["created_at"], message["direction"], message["status"], message["body"])
# More? Repeat with starting_after = data["data"][-1]["id"]
print("has_more:", data["has_more"])
```

```json 200 OK theme={null}
{
  "data": [
    {
      "id": "5f6a7b8c-9d0e-4f1a-8b2c-3d4e5f6a7b8c",
      "direction": "inbound",
      "created_at": "2026-11-10T15:06:41.518204Z",
      "status": "delivered",
      "to": "+14155551234",
      "body": "Thanks! Can we talk tomorrow?",
      "contact_id": "c8a1f4e2-3b9d-4f7c-a8e5-1d2c3b4a5e6f",
      "conversation_id": "3a4b5c6d-7e8f-9a0b-1c2d-3e4f5a6b7c8d",
      "conversation_kind": "one_to_one",
      "chat_guid": null,
      "channel": "imessage",
      "sent_at": "2026-11-10T15:06:40.902Z",
      "held_until": null,
      "held_reason": null,
      "effect": null,
      "reply_to_message_id": null,
      "attachments": []
    },
    {
      "id": "8b3a4e72-1c2d-4e5f-9a0b-2c3d4e5f6a7b",
      "direction": "outbound",
      "created_at": "2026-11-10T15:04:10.112730Z",
      "status": "read",
      "to": "+14155551234",
      "body": "Hey Sam — quick check-in about your order.",
      "contact_id": "c8a1f4e2-3b9d-4f7c-a8e5-1d2c3b4a5e6f",
      "conversation_id": "3a4b5c6d-7e8f-9a0b-1c2d-3e4f5a6b7c8d",
      "conversation_kind": "one_to_one",
      "chat_guid": null,
      "channel": "imessage",
      "sent_at": "2026-11-10T15:04:12.381Z",
      "held_until": null,
      "held_reason": null,
      "effect": null,
      "reply_to_message_id": null,
      "attachments": []
    }
  ],
  "has_more": true
}
```

```json 422 Unprocessable Entity theme={null}
{
  "detail": {
    "error": "invalid_cursor",
    "message": "starting_after is not the id of one of your items"
  }
}
```

```json 429 Too Many Requests theme={null}
{
  "detail": {
    "error": "rate_limited",
    "message": "Too many list requests; wait 18s (limit 120 a minute per account)."
  }
}
```

#### Responses

**200 OK**

`data` holds up to `limit` messages, newest first: by `created_at`, then by `id` for messages recorded in the same microsecond. Each item is exactly what [Retrieve a message](https://docs.ibubbl.com/api-reference/messages/retrieve.md) returns for that message. `has_more` is `true` when more messages match; to get them, repeat the request with `starting_after` set to the `id` of the last item in `data`. An empty `data` comes with `has_more: false`.

* `direction` is `inbound` or `outbound`.
* `created_at` is when iBubbl recorded the message, in UTC with microseconds. It never changes, which is why the list sorts and filters by it. `sent_at` is when the message went out or arrived, and can be earlier than `created_at` for an inbound message.
* For an inbound message, `status` is `delivered`, or `read` once someone on your account has read it in the dashboard. `to` is the contact's number (who sent it), and `channel` is how it arrived.

```json theme={null}
{
  "data": [
    {
      "id": "8b3a4e72-1c2d-4e5f-9a0b-2c3d4e5f6a7b",
      "direction": "outbound",
      "created_at": "2026-11-10T15:04:10.112730Z",
      "status": "read",
      "to": "+14155551234",
      "body": "Hey Sam — quick check-in about your order.",
      "contact_id": "c8a1f4e2-3b9d-4f7c-a8e5-1d2c3b4a5e6f",
      "conversation_id": "3a4b5c6d-7e8f-9a0b-1c2d-3e4f5a6b7c8d",
      "conversation_kind": "one_to_one",
      "chat_guid": null,
      "channel": "imessage",
      "sent_at": "2026-11-10T15:04:12.381Z",
      "held_until": null,
      "held_reason": null,
      "effect": null,
      "reply_to_message_id": null,
      "attachments": []
    }
  ],
  "has_more": false
}
```

**401 Unauthorized**

```json theme={null}
{
  "detail": {
    "error": "unauthorized",
    "message": "Invalid or revoked API key"
  }
}
```

Other `message` values: `Authorization Bearer token required`, `API key required (use Authorization: Bearer ib_pk_…)`, `Invalid API key format`, `Customer account not found`.

**403 Forbidden**

```json theme={null}
{
  "detail": {
    "error": "forbidden",
    "message": "Account is suspended"
  }
}
```

Your iBubbl account is suspended or cancelled (`message` is then `Account is cancelled`). Every API-key endpoint returns this.

**422 Unprocessable Entity**

```json theme={null}
{
  "detail": {
    "error": "validation_error",
    "message": "Unknown query parameter: startingAfter. Allowed: chat_guid, contact_id, conversation_id, created_after, created_before, direction, limit, starting_after, status"
  }
}
```

`validation_error`: a query parameter is unknown, repeated or invalid (`limit` outside 1–100, an ID that isn't a UUID, a time without a time zone, an unknown `direction` or `status`). `invalid_cursor`: `starting_after` is a UUID but not the ID of one of your messages.

**429 Too Many Requests**

```text theme={null}
Retry-After: 18
```

```json theme={null}
{
  "detail": {
    "error": "rate_limited",
    "message": "Too many list requests; wait 18s (limit 120 a minute per account)."
  }
}
```

Your account made more than 120 list requests in the last 60 seconds. `Retry-After` is the number of whole seconds until the oldest of them stops counting. Wait that long, then send the same request again; the refused request didn't count. The limit is checked after the API key, so a bad key is still `401`.


## OpenAPI

````yaml GET /v1/messages
openapi: 3.1.0
info:
  title: iBubbl API
  version: v1
  description: >-
    The iBubbl REST API. Send iMessages, manage contacts, and subscribe to
    webhook events from your backend.


    Authenticate every request with a Bearer API key (`ib_pk_<hex>`) — generate
    one from your dashboard's API Access settings. See the
    [Authentication](/authentication) guide.
servers:
  - url: https://api.ibubbl.com
security:
  - BearerAuth: []
tags:
  - name: Messages
  - name: Contacts
  - name: Conversations
  - name: Webhooks
  - name: Inbound Events
paths:
  /v1/messages:
    get:
      tags:
        - Messages
      summary: List messages
      description: >-
        List your messages, inbound and outbound, newest first. Use it to catch
        up after your webhook endpoint was down, or to read a conversation's
        history.


        Results are paginated: `has_more` tells you whether there is another
        page, and you get it by passing the `id` of the last message as
        `starting_after`. Pages are stable while new messages arrive: nothing is
        skipped or repeated. See [Pagination](/concepts/pagination).


        Filters combine with AND. A filter value that matches nothing (including
        another account's `contact_id` or `chat_guid`) returns an empty page. An
        unknown or repeated query parameter returns `422 validation_error`.


        Messages stay listed after their contact is deleted or blocked.


        Lists allow 120 requests a minute per account, across all your API keys
        and all lists. Over that, the answer is `429 rate_limited` with a
        `Retry-After` header in seconds.
      operationId: v1_list_messages_v1_messages_get
      parameters:
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            maximum: 100
            minimum: 1
            description: How many items to return, 1 to 100. Defaults to 50.
            default: 50
            title: Limit
          description: How many items to return, 1 to 100. Defaults to 50.
        - name: starting_after
          in: query
          required: false
          schema:
            anyOf:
              - type: string
                format: uuid
              - type: 'null'
            description: >-
              The `id` of the last item on the page you already have. Returns
              the items that come after it, in the same order. Leave it out for
              the first page. An `id` that isn't one of yours returns `422
              invalid_cursor`.
            title: Starting After
          description: >-
            The `id` of the last item on the page you already have. Returns the
            items that come after it, in the same order. Leave it out for the
            first page. An `id` that isn't one of yours returns `422
            invalid_cursor`.
        - name: contact_id
          in: query
          required: false
          schema:
            anyOf:
              - type: string
                format: uuid
              - type: 'null'
            description: >-
              Only messages with this contact: the 1:1 conversation, plus group
              messages they sent or that were addressed to them as the group's
              primary contact. For one whole conversation, use
              `conversation_id`.
            title: Contact Id
          description: >-
            Only messages with this contact: the 1:1 conversation, plus group
            messages they sent or that were addressed to them as the group's
            primary contact. For one whole conversation, use `conversation_id`.
        - name: conversation_id
          in: query
          required: false
          schema:
            anyOf:
              - type: string
                format: uuid
              - type: 'null'
            description: Only messages in this conversation (1:1 or group).
            title: Conversation Id
          description: Only messages in this conversation (1:1 or group).
        - name: chat_guid
          in: query
          required: false
          schema:
            anyOf:
              - type: string
                minLength: 1
              - type: 'null'
            description: >-
              Only messages in the iMessage group with this `chat_guid`. It
              changes when a participant is added; the group's `conversation_id`
              doesn't.
            title: Chat Guid
          description: >-
            Only messages in the iMessage group with this `chat_guid`. It
            changes when a participant is added; the group's `conversation_id`
            doesn't.
        - name: direction
          in: query
          required: false
          schema:
            anyOf:
              - enum:
                  - inbound
                  - outbound
                type: string
              - type: 'null'
            description: Only `inbound` or only `outbound` messages.
            title: Direction
          description: Only `inbound` or only `outbound` messages.
        - name: status
          in: query
          required: false
          schema:
            anyOf:
              - enum:
                  - queued
                  - pending
                  - sent
                  - delivered
                  - read
                  - failed
                  - expired
                  - cancelled
                type: string
              - type: 'null'
            description: Only messages with this `status`.
            title: Status
          description: Only messages with this `status`.
        - name: created_after
          in: query
          required: false
          schema:
            anyOf:
              - type: string
                format: date-time
              - type: 'null'
            description: >-
              Only messages with `created_at` strictly after this time. ISO 8601
              with a time zone, e.g. `2026-11-10T09:30:00Z`; in a query string,
              write `Z` or encode `+` as `%2B`.
            title: Created After
          description: >-
            Only messages with `created_at` strictly after this time. ISO 8601
            with a time zone, e.g. `2026-11-10T09:30:00Z`; in a query string,
            write `Z` or encode `+` as `%2B`.
        - name: created_before
          in: query
          required: false
          schema:
            anyOf:
              - type: string
                format: date-time
              - type: 'null'
            description: >-
              Only messages with `created_at` strictly before this time. Same
              format as `created_after`.
            title: Created Before
          description: >-
            Only messages with `created_at` strictly before this time. Same
            format as `created_after`.
      responses:
        '200':
          description: A page of messages.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageList'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '403':
          description: '`forbidden`: your iBubbl account is suspended or cancelled.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '422':
          description: >-
            `validation_error` (a bad, unknown or repeated query parameter, or
            `limit` outside 1–100) or `invalid_cursor` (`starting_after` is not
            one of your messages).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '429':
          description: >-
            `rate_limited`: more than 120 list requests in 60 seconds from your
            account (all keys and all lists count together). Wait `Retry-After`
            seconds, then send the same request again.
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
components:
  schemas:
    MessageList:
      properties:
        data:
          items:
            $ref: '#/components/schemas/Message'
          type: array
          title: Data
          description: >-
            Up to `limit` messages, newest first: by `created_at`, then by `id`
            for messages recorded in the same microsecond.
        has_more:
          type: boolean
          title: Has More
          description: >-
            Whether more messages match after the last one in `data`. To get
            them, repeat the request with `starting_after` set to that message's
            `id`.
      type: object
      required:
        - data
        - has_more
      title: MessageList
    ApiError:
      properties:
        detail:
          allOf:
            - $ref: '#/components/schemas/ApiErrorDetail'
          description: >-
            Error envelope. Every `/v1` error response wraps a stable `error`
            code and a human-readable `message` in `detail`.
      type: object
      required:
        - detail
      title: ApiError
      example:
        detail:
          error: validation_error
          message: >-
            Exactly one of contact_id, to, chat_guid, or participant_phones is
            required
    Message:
      properties:
        id:
          type: string
          title: Id
          description: Unique message identifier (UUID).
        direction:
          type: string
          enum:
            - inbound
            - outbound
          title: Direction
          description: >-
            `outbound` = sent from your line (through the API, the dashboard or
            an automation); `inbound` = received from a contact. An inbound
            message has `status` `delivered`, or `read` once it has been read in
            the dashboard.
        created_at:
          type: string
          title: Created At
          description: >-
            ISO 8601 UTC timestamp, with microseconds and a `Z`, of when iBubbl
            recorded the message. It never changes, so it is what `GET
            /v1/messages` sorts and filters by; pass it back as `created_after`
            / `created_before` unchanged.
          examples:
            - '2026-05-17T14:23:45.123456Z'
        status:
          type: string
          enum:
            - queued
            - pending
            - sent
            - delivered
            - read
            - failed
            - expired
            - cancelled
          title: Status
          description: >-
            Lifecycle state. `pending` = accepted and on its way out; it may be
            waiting for the contact's working hours or the line's hourly limit
            for new contacts (see `held_until`). `queued` = parked by a capacity
            hold (`hourly_cap_hit` / `line_offline`), retried automatically.
            `sent` / `delivered` / `read` = delivery progression. `failed` = the
            send failed — see webhook `message.failed` for the reason; it can
            follow `sent` (or a `read` with no confirmed delivery) when iMessage
            reports the send failed after accepting it (`failed_reason`
            `imessage_undeliverable` / `imessage_error:<code>`), and such a
            message can still move to `delivered` / `read` if Apple later
            confirms it. `expired` = still queued after an hour, so dropped; it
            will not send. `cancelled` = stopped in the dashboard before it was
            sent; it will not send (webhook `message.cancelled`).
        to:
          anyOf:
            - type: string
            - type: 'null'
          title: To
          description: >-
            The contact's phone number (E.164) for 1:1 messages: the destination
            of an outbound message, and the sender of an inbound one. Null for
            group messages — the group is identified by `chat_guid` instead.
          examples:
            - '+14155551234'
        body:
          type: string
          title: Body
          description: The message text as sent.
        contact_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Contact Id
          description: >-
            ID of the contact this message was sent to. For groups, this is the
            'primary' participant the message was addressed to (the first
            participant in `participant_phones` on a new group create); the
            conversation's full participant list is available via the
            conversation.
        conversation_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Conversation Id
          description: >-
            ID of the conversation this message belongs to. Stable for the
            lifetime of the conversation; use it to fetch the thread or
            correlate webhook events.
        conversation_kind:
          type: string
          enum:
            - one_to_one
            - group
          title: Conversation Kind
          description: >-
            `one_to_one` for sends to a single contact, `group` for iMessage
            groups (2+ participants in addition to your iBubbl line).
          default: one_to_one
        chat_guid:
          anyOf:
            - type: string
            - type: 'null'
          title: Chat Guid
          description: >-
            Opaque identifier for the group chat (e.g. `any;+;<hex>`). Returned
            for `group` messages — use it to address later messages to the same
            group via the `chat_guid` request shape. Null for `one_to_one`
            messages, and for a brand-new group until the group has been created
            in iMessage (that happens when the first message goes out, which can
            wait for sending hours); poll `GET /v1/messages/{id}` to see it fill
            in. It changes when a participant is added to the group.
          examples:
            - any;+;067ace6caf6c43aaa2f7d643975e15ea
        channel:
          anyOf:
            - type: string
              enum:
                - imessage
                - sms
            - type: 'null'
          title: Channel
          description: >-
            How the message travelled: `imessage`, or `sms` (a text, including
            RCS). For an outbound message, how it actually went out (`sms` when
            the recipient couldn't be reached on iMessage); null until it has
            been sent. For an inbound message, how it arrived; null when that
            wasn't recorded.
        sent_at:
          anyOf:
            - type: string
            - type: 'null'
          title: Sent At
          description: >-
            ISO 8601 UTC timestamp. Set when the message is accepted, then
            replaced by the actual send time once it goes out. Use `status`
            (`sent` / `delivered` / `read`), not `sent_at`, to tell whether it
            has actually gone out.
          examples:
            - '2026-05-17T14:23:45.123Z'
        held_until:
          anyOf:
            - type: string
            - type: 'null'
          title: Held Until
          description: >-
            While a `pending` message is being held, the expected time (ISO 8601
            UTC) it will go out: the next opening of the contact's working
            hours; for `hourly_limit`, an estimate of when a slot frees.
            Recomputed within about 10 seconds. Null when the message is not
            held, when `held_reason` is `working_hours` but no sending day is
            enabled, and when it is `hourly_limit` with no estimate.
          examples:
            - '2026-10-08T16:00:00+00:00'
        held_reason:
          anyOf:
            - type: string
              enum:
                - working_hours
                - hourly_limit
            - type: 'null'
          title: Held Reason
          description: >-
            Why a `pending` message is being held right now: `working_hours`
            (outside the contact's working hours) or `hourly_limit` (the line
            has started its limit of new contacts for this hour; the message
            goes out by itself when a slot frees, at about `held_until`). Null
            when it is not held.
        effect:
          anyOf:
            - type: string
              enum:
                - slam
                - loud
                - gentle
                - invisible
                - echo
                - spotlight
                - balloons
                - confetti
                - love
                - lasers
                - fireworks
                - celebration
                - shooting_star
            - type: 'null'
          title: Effect
          description: >-
            The iMessage send effect requested for this message, or null. It
            shows on the recipient's device only when `channel` is `imessage`.
        reply_to_message_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Reply To Message Id
          description: >-
            The ID of the message this one quotes as an inline reply, or null.
            The quote shows on the recipient's device only when `channel` is
            `imessage`.
        attachments:
          items:
            $ref: '#/components/schemas/MessageAttachment'
          type: array
          title: Attachments
          description: >-
            The files on this message, in the order they were sent: sent with
            `attachments`, from the dashboard or an automation, or received from
            the contact. Empty when there are none. File contents and URLs are
            not returned.
      type: object
      required:
        - id
        - direction
        - created_at
        - status
        - body
        - attachments
      title: Message
      example:
        attachments: []
        body: Hey Sam — quick check-in about your order.
        contact_id: c8a1f4e2-3b9d-4f7c-a8e5-1d2c3b4a5e6f
        conversation_id: 3a4b5c6d-7e8f-9a0b-1c2d-3e4f5a6b7c8d
        conversation_kind: one_to_one
        created_at: '2026-10-08T11:40:44.770512Z'
        direction: outbound
        held_reason: working_hours
        held_until: '2026-10-08T16:00:00+00:00'
        id: 8b3a4e72-1c2d-4e5f-9a0b-2c3d4e5f6a7b
        sent_at: '2026-10-08T11:40:44.770Z'
        status: pending
        to: '+14155551234'
    ApiErrorDetail:
      properties:
        error:
          type: string
          title: Error
          description: >-
            Stable machine-readable error code. Use this for branching logic in
            your integration; the human-readable `message` is subject to change.
            See the Error Reference for the catalog.
          examples:
            - validation_error
        message:
          type: string
          title: Message
          description: Human-readable description of what went wrong.
          examples:
            - >-
              Exactly one of contact_id, to, chat_guid, or participant_phones is
              required
      type: object
      required:
        - error
        - message
      title: ApiErrorDetail
    MessageAttachment:
      properties:
        kind:
          type: string
          enum:
            - image
            - gif
            - video
            - audio
            - file
          title: Kind
          description: '`file` is a PDF (or another document).'
        mime_type:
          type: string
          title: Mime Type
          examples:
            - image/jpeg
        size_bytes:
          type: integer
          title: Size Bytes
          description: >-
            Size in bytes. An inbound file can show `0` for a few seconds, until
            iBubbl has received it.
      type: object
      required:
        - kind
        - mime_type
        - size_bytes
      title: MessageAttachment
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: ib_pk_<64 hex>
      description: >-
        Bearer API key. Format: `Authorization: Bearer ib_pk_<64 hex>` (70
        characters). Generate keys from Dashboard → Settings → API Access.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.