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

# List the events feed

> Lists the events of the last 72 hours that matched a subscription of your account, newest first, with a cursor.

* **Credential:** an account API key. A trial key returns `401 unauthorized`.
* **Line-scoped keys:** the list of a [line-scoped key](/authentication#line-scoped-keys) is not
  applied here: the key reads the events of every line of the account, message content included.
* **`Idempotency-Key`:** not needed: the operation changes nothing. See
  [Retrying safely](/idempotency#retrying-safely).
* **Events:** none. The operation lists events: it replays nothing.
* **Personal data:** each item is a full event, with message text, handles, contact names and
  attachment file names. Request it only when needed, do not copy it into logs, tickets or other
  tools, and refer to a contact by an id of your own.
* **Guide:** [Events feed](/webhooks/pulling-events) explains what the feed holds, how to walk it and
  its limits. An event is listed only if it matched an active subscription of your account when it
  occurred: an account without a subscription has an empty feed.

## Errors

| Status | `error.code` | When |
| - | - | - |
| 400 | `validation_failed` | `since` is missing. `since` or `until` is not a timestamp in ISO 8601, in UTC, ending with `Z`. `event` is neither an event type, nor a family wildcard, nor `*`. `line_id` does not have the form of a line id. `limit` is outside 1 to 100. |
| 400 | `invalid_cursor` | `cursor` is not a cursor this operation returned. |

The errors that every operation shares are in [Errors](/errors-and-rate-limits#errors).


## OpenAPI

````yaml GET /v1/webhooks/events
openapi: 3.0.0
info:
  title: iSnap API
  version: 2.45.0
  description: >-
    The iSnap API sends and receives iMessage, RCS and SMS on real phone lines,
    manages those lines, and reports events through webhooks. Every message is
    sent to a real recipient, with an `isnap_live_` key and with an
    `isnap_test_` key alike. Retry a `429` after `Retry-After` seconds. Retry a
    `500` or a `503` up to 2 times, with exponential backoff. Do not retry any
    other `4xx`: fix the request. Retry a write only on an operation that honors
    `Idempotency-Key`, with the key of the first attempt. Responses carry
    personal data: handles, names and message text.
servers:
  - url: https://api.isnap.ai
security:
  - bearerAuth: []
paths:
  /v1/webhooks/events:
    get:
      summary: List the events feed
      description: >-
        Lists the events recorded for the account in the last 72 hours, newest
        first, one item per `event_id`, whatever the outcome of their
        deliveries. Accepts an API key; a line-scoped key reads the events of
        every line of the account, message content included. An event is
        recorded only if, when it occurred, it matched at least one webhook
        subscription of the account that was active and not suspended: an
        account without a webhook subscription has an empty feed, and the feed
        does not hold what a suspended or inactive subscription missed. Each
        item is the event as delivered, with the same `event_id`. `since` is
        required. The cursor does not carry the filters: send the same filters
        on every page. Stop when `has_more` is `false`: `next_cursor` is then
        `null`. A cursor that points past the 72 hours returns an empty page
        with `has_more: false`. Each item carries a whole event, which can
        include message text, handles, contact names and attachment file names:
        this is personal data.
      parameters:
        - schema:
            type: string
            format: date-time
            description: >-
              Start of the window, inclusive: ISO 8601 in UTC ending in `Z`. A
              UTC offset such as `+02:00` returns `400 validation_failed`. A
              value older than 72 hours is raised to 72 hours ago, without an
              error.
            example: '2026-10-08T12:00:00Z'
          required: true
          description: >-
            Start of the window, inclusive: ISO 8601 in UTC ending in `Z`. A UTC
            offset such as `+02:00` returns `400 validation_failed`. A value
            older than 72 hours is raised to 72 hours ago, without an error.
          name: since
          in: query
        - schema:
            type: string
            format: date-time
            description: >-
              End of the window, inclusive: ISO 8601 in UTC ending in `Z`.
              Default: the time of the request. When it is earlier than `since`,
              the page is empty.
            example: '2026-10-08T18:00:00Z'
          required: false
          description: >-
            End of the window, inclusive: ISO 8601 in UTC ending in `Z`.
            Default: the time of the request. When it is earlier than `since`,
            the page is empty.
          name: until
          in: query
        - schema:
            $ref: '#/components/schemas/WebhookEventName'
          required: false
          description: >-
            An exact event type such as `message.received`, a family wildcard
            such as `line.*`, or `*` for every event. A wildcard for a family
            that does not exist is accepted and matches nothing. `webhook.test`
            is never delivered through an event filter: iSnap sends it only to a
            suspended webhook subscription, to check whether its URL responds
            again.
          name: event
          in: query
        - schema:
            type: string
            pattern: ^line_[0-9A-Za-z]{25}$
            description: >-
              Keep the events tied to this line. The events of a trial are tied
              to the line the trial runs on: pass its `pool_line_id` to keep
              them. Events tied to no line are excluded. An id that matches no
              line returns an empty page.
            example: line_2k9Qp7RtY4mNb8VcXs3Wd6Lf1
          required: false
          description: >-
            Keep the events tied to this line. The events of a trial are tied to
            the line the trial runs on: pass its `pool_line_id` to keep them.
            Events tied to no line are excluded. An id that matches no line
            returns an empty page.
          name: line_id
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 100
            description: 'Number of events per page, from 1 to 100. Default: 100.'
          required: false
          description: 'Number of events per page, from 1 to 100. Default: 100.'
          name: limit
          in: query
        - schema:
            type: string
            description: >-
              The `next_cursor` of the previous page. Omit it for the first
              page. Send the same filters on every page.
          required: false
          description: >-
            The `next_cursor` of the previous page. Omit it for the first page.
            Send the same filters on every page.
          name: cursor
          in: query
      responses:
        '200':
          description: One page of events.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEventsEnvelope'
        '400':
          description: >-
            Invalid request. `error.code` is `validation_failed` when a
            parameter, a header or the body does not match its schema:
            `error.issues` then lists each problem. It is `invalid_cursor` when
            `cursor` cannot be read.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '401':
          description: No valid credential. `error.code` is `unauthorized`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          description: >-
            Too many requests. `error.code` is `rate_limit_exceeded` when more
            than 100 requests came from the same network address in 60 seconds,
            whatever their API key or account: wait `error.retry_after` seconds.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '500':
          description: >-
            Unexpected failure. `error.code` is `internal_error`. An operation
            that takes a JSON body also returns it when the body, sent as
            `application/json`, is not valid JSON. Quote `trace_id` when you
            report it to iSnap.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
      security:
        - bearerAuth: []
components:
  schemas:
    WebhookEventName:
      type: string
      enum:
        - message.queued
        - message.sent
        - message.delivered
        - message.read
        - message.failed
        - message.received
        - message.scheduled
        - message.cancelled
        - message.fallback_triggered
        - reaction.added
        - reaction.received
        - reaction.removed
        - line.connected
        - line.disconnected
        - line.offline
        - line.degraded
        - line.apple_id_flagged
        - line.quota_warning
        - line.quota_exceeded
        - line.capability_changed
        - line.terminated
        - line.variant_changed
        - line.variant_scheduled
        - line.variant_unscheduled
        - typing_indicator.started
        - typing_indicator.stopped
        - trial.linked
        - trial.dormant
        - trial.reactivated
        - trial.bind_conflict
        - trial.revoked
        - binding.released
        - pre_order.fulfilled
        - pre_order.cancelled
        - macos_session.rented
        - macos_session.released
        - webhook.test
        - '*'
        - message.*
        - reaction.*
        - line.*
        - typing_indicator.*
        - trial.*
        - binding.*
        - pre_order.*
        - macos_session.*
        - webhook.*
      description: >-
        An exact event type such as `message.received`, a family wildcard such
        as `line.*`, or `*` for every event. A wildcard for a family that does
        not exist is accepted and matches nothing. `webhook.test` is never
        delivered through an event filter: iSnap sends it only to a suspended
        webhook subscription, to check whether its URL responds again.
    WebhookEventsEnvelope:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
          description: Always `true` on a success response.
        data:
          type: object
          properties:
            items:
              type: array
              items:
                $ref: '#/components/schemas/WebhookEventItem'
              description: Events, newest first, one item per `event_id`.
            has_more:
              type: boolean
              description: '`true` when another page exists.'
            next_cursor:
              type: string
              nullable: true
              description: >-
                Cursor of the next page when `has_more` is `true`, otherwise
                `null`. Send it as `cursor`.
          required:
            - items
            - has_more
            - next_cursor
          description: One page of events.
        trace_id:
          type: string
          description: >-
            Trace id of the request that produced this response: 32 lowercase
            hexadecimal characters. Quote it when you report a problem to iSnap.
        request_id:
          type: string
          description: >-
            Id of the request that produced this response: `req_` followed by 25
            letters or digits.
      required:
        - success
        - data
        - trace_id
        - request_id
    ErrorEnvelope:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - false
          description: Always `false` on an error response.
        data:
          nullable: true
          description: Always `null` on an error response.
        error:
          type: object
          properties:
            status:
              type: integer
              description: The HTTP status of the response.
            code:
              type: string
              description: >-
                Stable machine-readable code that names the refusal. Branch on
                this value.
            message:
              type: string
              description: >-
                Text for a person. It can change between versions: do not branch
                on it.
            retry_after:
              type: integer
              nullable: true
              description: >-
                Seconds to wait before the next attempt. Set on the `429`
                responses that know a delay, where the `Retry-After` header
                carries the same value. When it is above 60 seconds, do not wait
                in a request: schedule the call, or report the time. `null` on
                every other error.
            retry_at:
              type: string
              nullable: true
              description: >-
                ISO 8601 timestamp at which the refusal ends. Set only on `429
                rebind_cap_reached`. `null` on every other error.
            issues:
              type: array
              nullable: true
              items:
                type: object
                properties:
                  path:
                    type: array
                    items:
                      anyOf:
                        - type: string
                        - type: number
                    description: >-
                      Where the problem is: the field names and array indexes
                      that lead to it.
                  message:
                    type: string
                    description: Text for a person.
                  code:
                    type: string
                    description: >-
                      Kind of problem. On `validation_failed`, for example
                      `invalid_type`, `invalid_value`, `invalid_format`,
                      `invalid_union`, `invalid_key`, `invalid_element`,
                      `too_small`, `too_big`, `not_multiple_of`,
                      `unrecognized_keys` or `custom`. The list is open: read
                      `path` and `message`.
                  min:
                    type: integer
                    description: >-
                      Smallest accepted value. Present only on
                      `limit_out_of_bounds`, `mac_quantity_not_a_pack`,
                      `byop_reduction_strands_mac_sessions` and
                      `byop_reduction_strands_byod_lines`.
                  max:
                    type: integer
                    description: >-
                      Largest accepted value. Present only on
                      `limit_out_of_bounds` and
                      `mac_sessions_exceed_byop_lines`, and on the `too_big`
                      issue of an `Idempotency-Key` header longer than 255
                      characters.
                required:
                  - path
                  - message
                  - code
              description: >-
                Problems found in the request, one entry each. Set on most `400
                validation_failed` responses and on the refusals that name a
                field: a refused `handle` of `POST /v1/lookup` has `issues:
                null`. `null` on every other error.
          required:
            - status
            - code
            - message
            - retry_after
            - retry_at
            - issues
          description: >-
            What went wrong. The six fields are always present; `retry_after`,
            `retry_at` and `issues` are `null` when they do not apply.
        trace_id:
          type: string
          description: >-
            Trace id of the request that produced this response: 32 lowercase
            hexadecimal characters. Quote it when you report a problem to iSnap.
        request_id:
          type: string
          description: >-
            Id of the request that produced this response: `req_` followed by 25
            letters or digits.
      required:
        - success
        - data
        - error
        - trace_id
        - request_id
      description: The body of an error response.
    WebhookEventItem:
      type: object
      properties:
        api_version:
          type: string
          description: Always `v1`. It is not the version number of the API.
        event_id:
          type: string
          description: >-
            Id of the event: `evt_` followed by 25 letters or digits. Every
            subscription, attempt and replay carries the same value, which is
            also the `webhook-id` header of the delivery. Deduplicate on it.
        event_type:
          type: string
          description: Event type, for example `message.received`.
        created_at:
          type: string
          description: >-
            Timestamp at which iSnap recorded the event, ISO 8601 in UTC with
            milliseconds. The same on every attempt and replay. The time of the
            change itself is inside `data`.
        trace_id:
          type: string
          description: >-
            Trace id: 32 hexadecimal characters, always present. Do not use it
            to match an event to a request: an event does not always carry the
            `trace_id` of the request that caused it. Match on the ids inside
            `data`, such as `data.message.id`.
        data:
          type: object
          properties:
            metadata:
              type: object
              nullable: true
              additionalProperties:
                nullable: true
              description: >-
                Your metadata on the main resource of the event: the line for
                `line.*`, the message for `message.*`, the message reacted to
                for `reaction.*`, the hosted macOS session for
                `macos_session.*`, the trial for `trial.*`, the pre-order for
                `pre_order.*`. Always present. `null` when that resource has no
                metadata, and always `null` for `typing_indicator.*`,
                `binding.*` and `webhook.*`. The value is read when the event is
                recorded: retries and replays carry the same value.
            line_metadata:
              type: object
              nullable: true
              additionalProperties:
                nullable: true
              description: >-
                Your metadata on the line the event is tied to, when that line
                belongs to your account. Always present. `null` when the event
                is tied to no line, when the line has no metadata, and when the
                line is not yours. A `macos_session.*` event is tied to no line
                but carries the metadata of the line the session runs, or ran
                until its release, when that line is yours. On `line.*` events
                it equals `metadata`. The value is read when the event is
                recorded: retries and replays carry the same value.
          required:
            - metadata
            - line_metadata
          additionalProperties:
            nullable: true
          description: >-
            Payload of the event. Its fields depend on `event_type`. `metadata`
            and `line_metadata` are present on every event.
      required:
        - api_version
        - event_id
        - event_type
        - created_at
        - data
      description: An event, as delivered to a webhook subscription.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        An API key created in the iSnap dashboard, or a trial key, sent as
        `Authorization: Bearer <key>`. An API key starts with `isnap_live_` or
        `isnap_test_`; both act on the same account, lines and billing. A trial
        key acts on its trial only.

````

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