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

# List messages

> Lists published message metadata for this topic, newest IDs first.
Use the marker to continue through older messages. Message bodies
are not included. The optional filters intersect with this topic.


<Info>
  Requires the IAM action **`notifications:ListMessages`** on the topic. See [Notifications permissions](/notifications/permissions).
</Info>


## OpenAPI

````yaml /api-reference/specs/notifications.yaml get /v1/topics/{topic_id}/messages
openapi: 3.0.3
info:
  title: Basaltic Notifications API
  version: 1.0.0
  description: >
    Publish/subscribe notification topics with email and webhook delivery.


    A topic is a fan-out root. Subscriptions bind it to endpoints;

    publishing to the topic delivers to every confirmed subscription

    whose filter policy matches the message.


    **Publishing is asynchronous.** Publish returns 202 as soon as the

    notification is durable and queued: no delivery has happened yet.

    Fan-out into per-subscription deliveries runs on a worker, so

    publish latency does not grow with subscriber count. Poll

    `GET /v1/topics/{topic_id}/messages/{message_id}` for the fan-out state and

    `GET /v1/topics/{topic_id}/deliveries?message=...` for per-endpoint
    outcomes.


    **Subscriptions must be confirmed.** Subscribe creates the

    subscription in `pending_confirmation` and sends a token to the

    endpoint — a link for email, a `subscription_confirmation` POST for

    webhooks. Nothing is delivered until the endpoint owner presents

    that token back. The confirmation window is 72 hours; unconfirmed

    subscriptions are reclaimed after it. If the handshake never

    arrived, `POST /v1/topics/{topic_id}/subscriptions/{id}/resend-confirmation`
    mints a

    fresh one — the original token is not recoverable, only its hash is

    stored.


    **Webhook endpoints must be publicly routable.** Endpoints resolving

    to loopback, RFC1918, link-local, or unique-local addresses are

    refused at subscribe time and again at delivery time.


    **Webhook deliveries are signed.** Each POST carries

    `X-Basaltic-Signature: v1,t=<unix-seconds>,s=<hex>`, an HMAC-SHA256

    over `"<t>.<raw-request-body>"` keyed by the subscription's signing

    secret. The secret is returned once by Subscribe and is readable

    afterwards via the signing-secret endpoint. Verify by recomputing

    the MAC over the raw body you received — not a re-serialised copy —

    and reject timestamps more than five minutes from now.
  contact:
    name: Basaltic Support
    email: ping@basaltic.sh
  license:
    name: Proprietary
    url: https://basaltic.sh/terms
servers:
  - url: https://notifications.{region}.basaltic.sh
    description: Regional API endpoint
    variables:
      region:
        default: sa-saopaulo-1
        description: Region code
security:
  - BearerAuth: []
tags:
  - name: Topics
    description: Fan-out topics
  - name: Subscriptions
    description: Endpoint subscriptions and their confirmation handshake
  - name: Messages
    description: Publishing and delivery status
  - name: Confirmations
    description: Unauthenticated endpoint-owner actions
paths:
  /v1/topics/{topic_id}/messages:
    parameters:
      - $ref: '#/components/parameters/TopicId'
    get:
      tags:
        - Messages
      summary: List messages
      description: |
        Lists published message metadata for this topic, newest IDs first.
        Use the marker to continue through older messages. Message bodies
        are not included. The optional filters intersect with this topic.
      operationId: listMessages
      parameters:
        - name: crn
          in: query
          description: >-
            Exact message CRN. Foreign identities return an empty page;
            malformed CRNs are invalid.
          schema:
            type: string
            example: >-
              crn:notifications:sa-saopaulo-1:acme:message/019400aa-bbbb-7ccc-8ddd-eeeeffff0000
        - name: fanout_state
          in: query
          schema:
            type: string
            enum:
              - pending
              - complete
            example: complete
        - $ref: '#/components/parameters/Marker'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Paginated list of message metadata.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageListResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
components:
  parameters:
    TopicId:
      name: topic_id
      in: path
      required: true
      schema:
        type: string
        format: uuid
        example: a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d
    Marker:
      name: marker
      in: query
      description: Id of the last item on the previous page.
      schema:
        type: string
        format: uuid
        example: a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d
    Limit:
      name: limit
      in: query
      description: >-
        Maximum items to return. A larger value is clamped to the maximum rather
        than rejected, so page until `meta.has_more` is false.
      schema:
        type: integer
        default: 50
        minimum: 1
        maximum: 200
        example: 50
  schemas:
    MessageListResponse:
      type: object
      required:
        - messages
        - meta
      properties:
        messages:
          type: array
          items:
            $ref: '#/components/schemas/Message'
        meta:
          $ref: '#/components/schemas/PaginationMeta'
    Message:
      type: object
      required:
        - id
        - crn
        - fanout_state
        - delivery_count
        - published_at
      properties:
        crn:
          type: string
          example: >-
            crn:notifications:sa-saopaulo-1:acme:message/019400aa-bbbb-7ccc-8ddd-eeeeffff0000
        id:
          type: string
          format: uuid
          example: 019400aa-bbbb-7ccc-8ddd-eeeeffff0000
        subject:
          type: string
          example: Disk pressure on europa
        message_structure:
          type: string
          enum:
            - ''
            - json
          example: ''
        attributes:
          $ref: '#/components/schemas/MessageAttributes'
        fanout_state:
          type: string
          enum:
            - pending
            - complete
          description: '`pending` until the worker has expanded the message into deliveries.'
          example: complete
        delivery_count:
          type: integer
          description: >-
            Deliveries fan-out produced. Meaningful only once fanout_state is
            complete.
          example: 3
        published_at:
          type: string
          format: date-time
          example: '2026-01-18T11:45:00Z'
        fanned_out_at:
          type: string
          format: date-time
          nullable: true
          example: '2026-01-18T11:45:01Z'
    PaginationMeta:
      type: object
      properties:
        total:
          type: integer
          description: Total number of items
          example: 150
        limit:
          type: integer
          description: Number of items per page
          example: 20
        marker:
          type: string
          description: >-
            Opaque cursor for the next page. Pass it back as the `marker` query
            parameter; treat it as a token, not a value to parse.
          example: 550e8400-e29b-41d4-a716-446655440000
        has_more:
          type: boolean
          description: Whether there are more items
          example: true
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
            - request_id
          properties:
            code:
              type: string
              description: Error code identifying the type of error
              example: INVALID_INPUT
            message:
              type: string
              description: Human-readable error message
              example: Invalid request parameters
            params:
              type: object
              additionalProperties: true
              description: >-
                Optional non-sensitive values for interpolation of localized
                errors, keyed by error code. Never present for server errors.
              example:
                instances: 2
                pools: 0
            request_id:
              type: string
              format: uuid
              description: Request ID for debugging
              example: 550e8400-e29b-41d4-a716-446655440000
    MessageAttributes:
      type: object
      description: |
        Typed attributes carried with a notification and matched against
        subscription filter policies. At most 20 attributes; values at
        most 1024 bytes. Binary attributes are not accepted — they
        cannot be filtered on.
      additionalProperties:
        type: object
        required:
          - type
          - value
        properties:
          type:
            type: string
            enum:
              - String
              - Number
            example: String
          value:
            type: string
            example: critical
      example:
        severity:
          type: String
          value: critical
        latency:
          type: Number
          value: '250'
  responses:
    BadRequest:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: INVALID_INPUT
              message: Invalid request parameters
              request_id: 550e8400-e29b-41d4-a716-446655440000
    Unauthorized:
      description: Authentication required or token invalid
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: UNAUTHORIZED
              message: Authentication required
              request_id: 550e8400-e29b-41d4-a716-446655440000
    Forbidden:
      description: Insufficient permissions
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: ACCESS_DENIED
              message: You don't have permission to perform this action
              request_id: 550e8400-e29b-41d4-a716-446655440000
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: NOT_FOUND
              message: Resource not found
              request_id: 550e8400-e29b-41d4-a716-446655440000
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        An OAuth 2.0 bearer token, sent as `Authorization: Bearer <token>`.
        This is the recommended way to authenticate.

        Get one by exchanging a service account's access key pair at
        `POST /v1/oauth/token` with `grant_type=client_credentials`. It is the
        standard client-credentials grant, so any OAuth-aware library will
        obtain and refresh it for you.

        ```
        curl -s -u "$KEY_ID:$SECRET" -d grant_type=client_credentials \
          https://iam.basaltic.sh/v1/oauth/token
        ```

        Tokens last an hour by default. The same access key pair is separately
        your AWS SigV4 credential for the S3-compatible object endpoint, which
        speaks nothing else.

````

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