> ## 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.

# Cancel a message

> Cancels a queued or held message that the line's device has not taken.

* **Credential:** an API key. A trial key returns `401 unauthorized`.
* **Line-scoped keys:** a [line-scoped key](/authentication#line-scoped-keys) gets `404 not_found` for a message on a line outside its list.
* **`Idempotency-Key`:** not honored. A repeat of a cancel that succeeded returns `409 too_late_to_cancel`.
* **Events:** sends `message.cancelled`.
* **Personal data:** the response carries the handles in `to` and `from`, the text in `body`, the attachment file names and your `metadata`. 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.
* **What can be canceled:** a message whose `status` is `queued` or `scheduled`, and that the line's device has not taken. See [Canceling a message](/guides/sending-messages#canceling-a-message).
* **Sending limits:** a canceled message that had counted against the limits of the line stops counting against them.

## Errors

| Status | `error.code` | When |
| - | - | - |
| 400 | `validation_failed` | The id is not `msg_` followed by 25 characters. |
| 404 | `not_found` | The id is unknown, the message belongs to another account or to a trial, is on a line outside the list of a line-scoped key, or iSnap has deleted it. |
| 409 | `too_late_to_cancel` | The message is `sent`, `delivered`, `read`, `failed` or already `cancelled`, or it is `queued` and the line's device has taken it. On a `queued` message, the device goes on with the send. |

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


## OpenAPI

````yaml DELETE /v1/messages/{id}
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/messages/{id}:
    delete:
      summary: Cancel a message
      description: >-
        Cancels a message whose `status` is `queued` or `scheduled` and that the
        line's device has not taken. Returns the message with `status:
        cancelled` and `cancelled_at` set, and sends `message.cancelled`. A
        canceled message is not handed to the device again: a message that the
        device took and did not report on within 10 minutes can be canceled once
        iSnap has taken it back, and the device can still send the copy it kept.
        If it had counted against the line's sending limits, it no longer
        counts. Returns `409 too_late_to_cancel` when the message is `sent`,
        `delivered`, `read`, `failed` or already `cancelled`, and when it is
        `queued` and the device already has it. In that last case the message is
        not stopped: read it with `GET /v1/messages/{id}` to know its outcome.
        This operation cancels a send and deletes nothing: the message stays
        readable until iSnap deletes it, at least 72 hours after it recorded it.
        Accepts an API key.
      parameters:
        - schema:
            type: string
            pattern: ^msg_[0-9A-Za-z]{25}$
            description: 'Message id: `msg_` followed by 25 letters or digits.'
          required: true
          description: 'Message id: `msg_` followed by 25 letters or digits.'
          name: id
          in: path
      responses:
        '200':
          description: 'The canceled message, with `status: cancelled`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageV1Envelope'
        '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.
          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'
        '403':
          description: >-
            Refused. `error.code` is `forbidden`: the request carries neither an
            API key in its `Authorization` header nor the header
            `X-Requested-With: XMLHttpRequest`. A message on a line outside the
            key's `line_ids` returns `404`, not `403`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '404':
          description: >-
            Not found. `error.code` is `not_found`: the message does not exist,
            iSnap has deleted it (at least 72 hours after it recorded it), it
            belongs to another account or to a trial, or it is on a line outside
            the key's `line_ids`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '409':
          description: >-
            Conflict. `error.code` is `too_late_to_cancel`: the message is
            `sent`, `delivered`, `read`, `failed` or already `cancelled`, or it
            is `queued` and the line's device already has it.
          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:
    MessageV1Envelope:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
          description: Always `true` on a success response.
        data:
          $ref: '#/components/schemas/MessageV1'
        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.
    MessageV1:
      type: object
      properties:
        id:
          type: string
          description: 'Message id: `msg_` followed by 25 letters or digits.'
        line_id:
          type: string
          pattern: ^line_[0-9A-Za-z]{25}$
          description: Id of the line that sent or received the message.
        direction:
          $ref: '#/components/schemas/MessageDirection'
        kind:
          $ref: '#/components/schemas/MessageKind'
        to:
          type: string
          description: >-
            On an outbound message sent through the API, the recipient's phone
            number in E.164. On a message typed on the line's device, the
            contact's handle as the device reports it. On an inbound message,
            the line's number: on a shared line, the number that serves the
            contact. A contact's number is personal data.
        from:
          type: string
          description: >-
            On an outbound message, the line's number: an empty string when the
            line has no number, and on a shared line the number that serves the
            contact. On an inbound message, the sender's handle, a phone number
            or an email address of up to 255 characters: exactly as the line's
            device stores it, without normalization, or normalized on a shared
            line (E.164 for a phone number). A phone number can come in another
            form than E.164: before you compare it with a number you send to,
            bring both to E.164. A contact's handle is personal data.
        body:
          type: string
          nullable: true
          description: >-
            Text of the message. `null` when the message has no text: a message
            with attachments only, or a reaction. The text of an inbound message
            is cut to 10,000 characters.
        channel:
          $ref: '#/components/schemas/MessageChannel'
        service:
          $ref: '#/components/schemas/MessageService'
        status:
          $ref: '#/components/schemas/MessageStatus'
        effect:
          oneOf:
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - bubble
                  description: Always `bubble` for a bubble effect.
                name:
                  type: string
                  enum:
                    - slam
                    - loud
                    - gentle
                    - invisible
                  description: Name of the bubble effect.
              required:
                - type
                - name
              description: 'A bubble effect: an effect on the message bubble.'
            - type: object
              properties:
                type:
                  type: string
                  enum:
                    - screen
                  description: Always `screen` for a screen effect.
                name:
                  type: string
                  enum:
                    - confetti
                    - balloons
                    - love
                    - lasers
                    - fireworks
                    - celebration
                    - shooting_star
                    - echo
                    - spotlight
                  description: Name of the screen effect.
              required:
                - type
                - name
              description: 'A screen effect: a full-screen effect.'
            - nullable: true
          description: >-
            The iMessage effect of the message, or `null` when it has none. On
            an outbound message, the effect you sent. On an inbound message, the
            effect the sender used, when the line's device reports it.
        reply_to_message_id:
          type: string
          nullable: true
          description: >-
            Id of the message this message replies to, or `null`. It becomes
            `null` when iSnap deletes the message replied to.
        use_typing_indicator:
          type: boolean
          description: >-
            On an outbound message, whether the line's device shows the typing
            indicator to the recipient before it sends the message. A message
            sent with an API key on a line that is not an iMessage line always
            has `false`. It has no meaning on an inbound message.
        metadata:
          type: object
          nullable: true
          additionalProperties:
            nullable: true
          description: >-
            The `metadata` you sent with the message, unchanged. `null` when you
            sent none, and on an inbound message.
        attachments:
          type: array
          items:
            $ref: '#/components/schemas/MessageAttachmentV1'
          description: >-
            The files of the message, in order. Empty when the message has none.
            Files received with an inbound message are listed here too.
        reactions:
          type: array
          items:
            $ref: '#/components/schemas/MessageReactionV1'
          description: >-
            The reactions on the message, at most one per author. Empty when the
            message has none, and always empty on an entry whose `kind` is
            `reaction`. The line's own reaction appears as soon as the API
            accepts it, and disappears as soon as the API accepts its removal,
            before the line's device confirms either. It stays listed when the
            device fails to place it.
        scheduled_for:
          type: string
          nullable: true
          description: >-
            On a held message (`status: scheduled`), the planned departure time.
            On an outbound message that was not held, or that has left its hold,
            the same value as `queued_at`: read `sent_at` for the time the
            message was sent. `null` on an inbound message and on a message
            typed on the device of the line.
        schedule_reason:
          type: string
          nullable: true
          description: >-
            Why iSnap holds the message, while its `status` is `scheduled`.
            `minute_limit_exceeded`, `hourly_limit_exceeded`,
            `total_message_quota_exceeded`, `new_contact_quota_exceeded` or
            `known_contact_quota_exceeded`: a sending limit of the line is
            reached. `inter_message_delay` or `inter_new_contact_delay`: the
            spacing between two messages of the line. `quiet_hours`: the message
            was accepted outside the line's sending hours, counted in the
            recipient's local time. `carrier_retry`: on a shared line, the
            number that serves the contact is busy or offline. `pending_retry`:
            iSnap is retrying the release. A message held behind an earlier
            message to the same recipient takes the `schedule_reason` of that
            earlier message while the earlier one is held, and
            `inter_message_delay` (`carrier_retry` on a shared line) while the
            earlier one waits for the line's device: `schedule_reason` alone
            does not tell you that a message waits for an earlier one. `null` on
            a message that was never held, and `null` again once the message is
            released. Treat a value you do not know as a hold: more values can
            be added.
        reply_lane:
          type: boolean
          description: >-
            `true` when the message is in the reply lane: it answers a contact
            who wrote to the line in the last 24 hours, within the limits of the
            reply lane. Such a message is not held by the hourly limit, by the
            three 24-hour limits or by quiet hours. Set when the message is
            accepted. A held message enters the reply lane when its contact
            writes to the line while it waits, whatever held it, oldest first
            and within the same limits: the value then changes from `false` to
            `true`, once and never back, and the message is released without
            waiting for its `scheduled_for`, still after the earlier messages to
            the same recipient and within the per-minute limit and the spacing
            of the line.
        ignore_quiet_hours:
          type: boolean
          description: >-
            `true` when the message was sent with `ignore_quiet_hours: true` on
            a line that is not a shared line: quiet hours do not hold it.
            `false` otherwise, on a shared line, on an inbound message and on a
            message typed on the device of the line. Set when the message is
            accepted and never changed after that.
        queue_info:
          type: object
          nullable: true
          properties:
            queue_position:
              type: integer
              minimum: 0
              description: >-
                0 when the message leaves immediately. Otherwise the rank of the
                message among the line's held messages, starting at 1.
            is_new_contact:
              type: boolean
              description: >-
                `true` when the recipient is a new contact for the line: that
                number has not written to the line in the last 30 days, which is
                the default length of that period. `false` when the recipient is
                a known contact.
            daily_new_contacts_used:
              type: integer
              minimum: 0
              description: >-
                Distinct new contacts counted for the line in the last 24 hours,
                once this request is accepted.
            daily_new_contact_limit:
              type: integer
              minimum: 0
              description: The line's limit of distinct new contacts per rolling 24 hours.
            daily_known_contacts_used:
              type: integer
              minimum: 0
              description: >-
                Distinct known contacts counted for the line in the last 24
                hours, once this request is accepted.
            daily_known_contact_limit:
              type: integer
              minimum: 0
              description: >-
                The line's limit of distinct known contacts per rolling 24
                hours.
            daily_messages_used:
              type: integer
              minimum: 0
              description: >-
                Messages counted for the line in the last 24 hours, once this
                request is accepted. A held message counts when it is released,
                not when it is accepted.
            daily_total_message_limit:
              type: integer
              minimum: 0
              description: The line's limit of messages per rolling 24 hours.
            reply_lane:
              type: boolean
              description: The same value as `reply_lane` of the message.
            daily_replies_used:
              type: integer
              minimum: 0
              description: >-
                Reply-lane messages counted for the line in the last 24 hours,
                once this request is accepted.
            daily_reply_limit:
              type: integer
              minimum: 0
              description: The line's limit of reply-lane messages per rolling 24 hours.
            messages_ahead_in_queue:
              type: integer
              minimum: 0
              description: >-
                Number of held messages of the line planned to leave before this
                one. Present only when the message is held.
            daily_slot_of:
              type: string
              description: >-
                Date of the planned departure in the recipient's local time, as
                `YYYY-MM-DD`. Present only when iSnap placed the held message at
                a time in the line's sending hours.
            target_activity_hour:
              type: integer
              minimum: 0
              maximum: 23
              description: >-
                Hour of the planned departure in the recipient's local time, 0
                to 23. Present only with `daily_slot_of`.
            next_slot_available_at:
              type: string
              description: >-
                The planned departure time: the same value as `scheduled_for` of
                the message. Present only when the message is held.
            last_new_contact_sent_at:
              type: string
              description: >-
                When the line last sent a first message to a new contact.
                Present only when `schedule_reason` is
                `inter_new_contact_delay`.
            min_inter_new_contact_seconds:
              type: integer
              minimum: 0
              description: >-
                The line's minimum number of seconds between two first messages
                to new contacts. Present only when `schedule_reason` is
                `inter_new_contact_delay`.
            jitter_applied_seconds:
              type: integer
              minimum: 0
              description: >-
                Random number of seconds added to that minimum for this message.
                Present only when `schedule_reason` is
                `inter_new_contact_delay`.
          required:
            - queue_position
            - is_new_contact
            - daily_new_contacts_used
            - daily_new_contact_limit
            - daily_known_contacts_used
            - daily_known_contact_limit
            - daily_messages_used
            - daily_total_message_limit
            - reply_lane
            - daily_replies_used
            - daily_reply_limit
          description: >-
            The state of the line's sending limits when the message was
            accepted. Filled only in the response of `POST /v1/messages` to a
            new request: `null` on every read, in the response to a retry with
            the same `Idempotency-Key`, and in events.
        created_at:
          type: string
          description: >-
            When iSnap recorded the message. On an inbound message it can be
            later than `delivered_at`, when the line's device was offline.
        queued_at:
          type: string
          nullable: true
          description: >-
            When an outbound message entered the queue. `null` on an inbound
            message and on a message typed on the device of the line.
        sent_at:
          type: string
          nullable: true
          description: >-
            When the line's device confirmed that it sent the message. `null`
            until then, and on an inbound message.
        delivered_at:
          type: string
          nullable: true
          description: >-
            On an outbound message, the delivery time the line's device
            reported: `null` until it reports one. On an inbound message, the
            time the device received the message.
        read_at:
          type: string
          nullable: true
          description: >-
            On an outbound message, the time the line's device reported that the
            recipient read it. On an inbound message, the time it was marked as
            read with `POST /v1/chats/{chat_id}/read`. `null` until then.
        failed_at:
          type: string
          nullable: true
          description: >-
            When the message became `failed`. `null` otherwise. When the device
            of an iMessage line reports a failure after `sent`, `failed_at`
            holds the time of the send, not the time of the failure.
        error_code:
          type: string
          nullable: true
          description: >-
            `null` unless the message is `failed`. When iSnap failed the message
            itself: `carrier_unavailable` (the message waited 48 hours without
            reaching a device), `no_terminal_ack` (the line's device took the
            message and never reported an outcome) or `carrier_terminated` (the
            line was terminated while the message was waiting). `null` when the
            line's device reported the failure: read `error_message`.
        error_message:
          type: string
          nullable: true
          description: >-
            `null` unless the message is `failed`. A text that describes the
            failure. When the line's device reported the failure, it is the text
            the device gave, or `null` when it gave none.
        cancelled_at:
          type: string
          nullable: true
          description: When the message was canceled. `null` otherwise.
      required:
        - id
        - line_id
        - direction
        - kind
        - to
        - from
        - body
        - channel
        - service
        - status
        - effect
        - reply_to_message_id
        - use_typing_indicator
        - metadata
        - attachments
        - reactions
        - scheduled_for
        - schedule_reason
        - reply_lane
        - ignore_quiet_hours
        - queue_info
        - created_at
        - queued_at
        - sent_at
        - delivered_at
        - read_at
        - failed_at
        - error_code
        - error_message
        - cancelled_at
      description: >-
        A message sent or received by a line. The response of `POST
        /v1/messages`, the reads, the list items, the cancel response and the
        `message` field of the `message.*` events all carry this object. It has
        no chat id: the chat id is given by `GET /v1/chats` and by events. It
        carries personal data: the handles in `to` and `from`, the text in
        `body`, the file names of `attachments`, and what you put in `metadata`.
        Timestamps are ISO 8601 in UTC.
    MessageDirection:
      type: string
      enum:
        - outbound
        - inbound
      description: >-
        `outbound`: a message the line sent, through the API or typed on the
        line's device. `inbound`: a message the line received.
    MessageKind:
      type: string
      enum:
        - message
        - voice
        - reaction
      description: >-
        `message`: a message with text, attachments or both. `voice`: a voice
        note. `reaction`: a reaction, recorded as its own entry.
    MessageChannel:
      type: string
      enum:
        - auto
        - iMessage
        - SMS
        - RCS
      description: >-
        `auto` on a message sent through the API. On an inbound message and on a
        message typed on the line's device, the same value as `service`.
        `iMessage` on a reaction.
    MessageService:
      type: string
      nullable: true
      enum:
        - iMessage
        - SMS
        - RCS
        - null
      description: >-
        The service the line's device reports it used: `iMessage`, `SMS` or
        `RCS`. On an outbound message it is `null` until the device confirms the
        send, and it stays `null` when the send fails or when the device does
        not report the service. On an inbound message, the service the message
        arrived on.
    MessageStatus:
      type: string
      enum:
        - queued
        - scheduled
        - sent
        - delivered
        - read
        - failed
        - cancelled
      description: >-
        `queued`: accepted and waiting for the line's device, or with the
        device, which has not reported the outcome. `scheduled`: held by iSnap
        until `scheduled_for`. `sent`: the device reported that it sent the
        message. `delivered`: the device reported a delivery receipt; every
        inbound message, and every message typed on the line's device, is
        `delivered` from the start. `read`: the device reported that the
        recipient read an outbound message. `failed`: the message failed, or
        iSnap stopped waiting for its outcome (`error_code: no_terminal_ack`),
        in which case it can have reached the recipient. iSnap never resends it.
        `cancelled`: canceled with `DELETE /v1/messages/{id}` before the device
        took it. An outbound message moves from `scheduled` to `queued`, `sent`,
        `delivered` and `read`, and no status is guaranteed to follow `sent`,
        `delivered` or `read`. On an iMessage line, a message sent over SMS or
        RCS gets no `delivered` and no `read`, and a `failed` can still follow
        its `sent`. `failed` can follow any status except `cancelled`, including
        `delivered` and `read`. `cancelled` is final. Treat `failed` as final: a
        send confirmation that arrives after a failure reported by the device
        sets `status` back to `sent` while `failed_at` stays set. A delivery
        receipt can arrive before the device confirms the send, and `status`
        then returns to `sent` while `delivered_at` stays set: read the
        timestamps, not only `status`.
    MessageAttachmentV1:
      type: object
      properties:
        id:
          type: string
          pattern: ^att_[0-9A-Za-z]{25}$
          description: >-
            Attachment id: `att_` followed by 25 letters or digits. Read the
            file with `GET /v1/attachments/{id}`.
        content_type:
          type: string
          minLength: 1
          maxLength: 100
          description: >-
            Content type of the file, as declared when the attachment was
            created. `audio/x-caf` for an audio file that iSnap converted.
        filename:
          type: string
          minLength: 1
          maxLength: 255
          description: File name. It can carry personal data.
        size_bytes:
          type: integer
          minimum: 1
          description: >-
            Size in bytes, as declared when the attachment was created. For an
            audio file that iSnap converted, the size after conversion.
        duration_ms:
          type: integer
          nullable: true
          minimum: 0
          description: >-
            Duration in milliseconds of an audio file that iSnap converted.
            `null` on every other file.
      required:
        - id
        - content_type
        - filename
        - size_bytes
        - duration_ms
      description: >-
        A file of a message. It carries no download URL: call `GET
        /v1/attachments/{id}` to get one.
    MessageReactionV1:
      type: object
      properties:
        reaction_type:
          type: string
          enum:
            - love
            - like
            - dislike
            - laugh
            - emphasize
            - question
            - custom
          description: >-
            `love`, `like`, `dislike`, `laugh`, `emphasize` or `question`, or
            `custom` for an emoji reaction from the contact.
        reaction_emoji:
          type: string
          nullable: true
          description: >-
            The emoji of the reaction. For `custom`, the emoji the contact used,
            or `null` when the line's device did not report it.
        from_handle:
          type: string
          description: >-
            Handle of the author of the reaction: the contact's handle when
            `direction` is `inbound`, the line's number when it is `outbound`. A
            contact's handle is personal data.
        direction:
          type: string
          enum:
            - outbound
            - inbound
          description: >-
            `outbound`: the line's own reaction. `inbound`: a reaction from the
            contact.
        created_at:
          type: string
          description: When iSnap recorded the reaction.
      required:
        - reaction_type
        - reaction_emoji
        - from_handle
        - direction
        - created_at
      description: >-
        A reaction on a message. A message carries at most one reaction per
        author.
  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.