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

# List notifications

> Returns a cursor-paginated list of broadcasts in the calling organization, newest first.

Useful for a campaign history dashboard: each item carries current `status` + `stats`, so one call renders the whole history with live delivery counters.

See [Pagination](/api-reference/pagination) for the cursor pattern.

Scope: `notifications:read`.



## OpenAPI

````yaml /openapi.json get /v1/notifications
openapi: 3.1.0
info:
  title: VEXiON cards Public API
  description: >-
    ## Rate limiting


    Two independent layers, checked in this order:


    1. **Per-IP throttle (pre-authentication).** Applied to every `/v1` request
    BEFORE the API key is checked, keyed on the caller's IP address:
       - **600 requests/minute** per IP - a flood ceiling, `429 rate_limit_error` / `rate_limited`.
       - **20 failed authentications per 15 minutes** per IP - a key-guessing ceiling. Only responses that are `401` (missing/invalid/revoked key) count against this ceiling; a `403` from a valid key that simply lacks a scope does not. `429 rate_limit_error` / `too_many_failed_attempts`.

       Both ceilings send `Retry-After` (seconds).
    2. **Per-key, per-bucket limiter (post-authentication).** Documented per
    endpoint (see each operation's `429` response and the `rate_limit` field on
    the API Key resource) - e.g. 60/min default, 120/min for transactions, plus
    the notification-broadcast and lookup-filter buckets described on their own
    endpoints.


    ### Rate-limit response headers


    Every rate-limited response carries the legacy `X-RateLimit-Limit` /
    `X-RateLimit-Remaining` / `X-RateLimit-Reset` family (the last is an **epoch
    timestamp**) AND the IETF standards-track headers, side by side:


    - `RateLimit-Policy: "<bucket>";q=<quota>;w=<window seconds>` - the static
    policy for the bucket that was hit.

    - `RateLimit: "<bucket>";r=<remaining>;t=<seconds until reset>` - live
    state. **`t` is a DURATION (seconds remaining), not the epoch timestamp
    `X-RateLimit-Reset` carries - the two are never the same value.**
  version: 1.0.0
servers:
  - url: https://api.vexioncards.one
    description: Production
  - url: https://migration.api.vexioncards.one
    description: Sandbox
security:
  - apiKey: []
tags:
  - name: Customers
  - name: Cards
  - name: Transactions
  - name: Notifications
  - name: Locations
  - name: Products
  - name: API keys
  - name: Organization
  - name: Webhook endpoints
  - name: Events
  - name: Custom fields
  - name: Team members
  - name: Icons
paths:
  /v1/notifications:
    get:
      tags:
        - Notifications
      summary: List notifications
      description: >-
        Returns a cursor-paginated list of broadcasts in the calling
        organization, newest first.


        Useful for a campaign history dashboard: each item carries current
        `status` + `stats`, so one call renders the whole history with live
        delivery counters.


        See [Pagination](/api-reference/pagination) for the cursor pattern.


        Scope: `notifications:read`.
      operationId: listNotifications
      parameters:
        - name: status
          in: query
          description: Lifecycle filter - same vocabulary as `Notification.status`.
          required: false
          schema:
            type: string
            enum:
              - queued
              - scheduled
              - processing
              - completed
              - partial
              - failed
              - cancelled
        - name: created[gte]
          in: query
          required: false
          description: Lower bound on created_at - unix seconds or ISO-8601 (inclusive).
          schema:
            anyOf:
              - type: integer
                title: Unix seconds
              - type: string
                format: date-time
                title: ISO-8601
          example: 1782000000
        - name: created[lte]
          in: query
          required: false
          description: Upper bound on created_at - unix seconds or ISO-8601 (inclusive).
          schema:
            anyOf:
              - type: integer
                title: Unix seconds
              - type: string
                format: date-time
                title: ISO-8601
        - name: limit
          in: query
          description: 1-100. Default 25.
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
        - name: starting_after
          in: query
          required: false
          description: >-
            Cursor - the `ntf_` id of the last item on the previous page
            (forward). Numeric offset or page parameters are not supported;
            cursors are the only supported paging mechanism.
          schema:
            type: string
            pattern: ^ntf_[A-Za-z0-9]+$
        - name: ending_before
          in: query
          required: false
          description: Reverse cursor - returns items before this `ntf_` id.
          schema:
            type: string
            pattern: ^ntf_[A-Za-z0-9]+$
      responses:
        '200':
          description: Paginated notification list.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationList'
              examples:
                Campaign history:
                  summary: First page, one completed broadcast
                  value:
                    object: list
                    url: /v1/notifications
                    data:
                      - id: ntf_01J9P0G7K9C0RYHXJ2K7A4N5MZ
                        object: notification
                        title:
                          en: Summer special menu
                        body:
                          en: Try the new lime lemonade for 2.50 EUR.
                        audience:
                          card_ids:
                            - crd_sophcrprtvpmmnwxah2lomnkee
                        status: completed
                        schedule_at: null
                        sent_at: 1782134401
                        stats:
                          total: 121
                          audience_resolved_count: 121
                          apple_wallet:
                            total: 98
                            delivered: 96
                            failed: 2
                          google_wallet:
                            total: 23
                            delivered: 22
                            failed: 1
                          delivered: 118
                          failed: 3
                        created_at: 1782134400
                        completed_at: 1782134522
                        request_id: req_01J9P0G7K9C0RYHXJ2K7A4N5MZ
                    has_more: false
                Empty list:
                  summary: No broadcasts yet
                  value:
                    object: list
                    url: /v1/notifications
                    data: []
                    has_more: false
          headers: {}
        '400':
          description: Malformed body or missing required field.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers: {}
        '401':
          description: Missing, invalid, or revoked API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers: {}
        '403':
          description: API key lacks the required scope.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers: {}
        '429':
          description: Per-minute or per-day rate limit exceeded. Respect Retry-After.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers: {}
        '500':
          description: Server error. Retry-safe on idempotent calls.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers: {}
      deprecated: false
components:
  schemas:
    NotificationList:
      allOf:
        - $ref: '#/components/schemas/ListResponse'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Notification'
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - type
            - code
            - message
          properties:
            type:
              type: string
              enum:
                - invalid_request_error
                - authentication_error
                - permission_error
                - not_found_error
                - rate_limit_error
                - idempotency_error
                - api_error
            code:
              type: string
            message:
              type: string
            retry_after:
              type: integer
              description: >-
                Seconds to wait before retrying. Present on rate-limit (429) and
                idempotency-key-in-use (409) errors; mirrors the `Retry-After`
                HTTP header. Absent on error types that carry no retry guidance.
              example: 5
            param:
              type:
                - string
                - 'null'
            request_id:
              type: string
            doc_url:
              type: string
              format: uri
            field_errors:
              type: array
              description: >-
                Per-field errors on a 422. At most 100 entries: a request with
                more errors gets the first 100.
              items:
                type: object
                properties:
                  param:
                    type: string
                  code:
                    type: string
                  message:
                    type: string
                  expected_currency:
                    type: string
                    description: >-
                      On `currency_mismatch`: the business currency the request
                      must use. Absent on every other field error.
          description: >-
            The error payload: type (category), code (machine-readable), message
            (human-readable), retry_after (seconds, on
            rate-limit/idempotency-in-use errors only), param (offending field),
            request_id, doc_url, field_errors[].
      description: >-
        Standard error envelope. Branch on `error.code`; include
        `error.request_id` in support requests. See the Errors guide.
    ListResponse:
      type: object
      required:
        - object
        - data
        - has_more
      properties:
        object:
          type: string
          enum:
            - list
          description: Always `"list"`.
        data:
          type: array
          items: {}
          description: Array of the requested resource type.
        has_more:
          type: boolean
          description: True when more pages exist.
        next_cursor:
          type:
            - string
            - 'null'
          description: >-
            Cursor for the next page **in the direction you are already
            paging**, or `null` when this page ends the collection. `has_more:
            true` always comes with a non-null `next_cursor`.


            Feed it back to the SAME parameter you used: `starting_after` when
            paging forward (the default), or `ending_before` when paging
            backward. Treat it as opaque and do not parse it.


            You no longer need to take the last object's `id` yourself. That
            still works and is unchanged, but deriving the cursor from the page
            put the burden of knowing the sort direction on you, and it broke
            silently on any endpoint whose cursor is not the object id.
          example: cus_iofv5j4hn6bphinmmyat27tc5y
        url:
          type: string
          description: Stable collection URL.
      description: >-
        Standard cursor-pagination envelope - see
        [Pagination](/api-reference/pagination).
    Notification:
      type: object
      description: >-
        A broadcast push notification. Created via POST /v1/notifications,
        delivered asynchronously to wallet passes (Apple Wallet + Google
        Wallet). The stored DTO always shows the UNRENDERED template -
        per-recipient rendered text is not retrievable after the fact.
      required:
        - id
        - object
        - title
        - body
        - status
        - stats
        - created_at
      properties:
        id:
          type: string
          pattern: ^ntf_[A-Za-z0-9]+$
          description: Notification identifier. Opaque, `ntf_` prefix. Immutable.
          example: ntf_01J9P0G7K9C0RYHXJ2K7A4N5MZ
        object:
          type: string
          const: notification
          description: Resource type discriminator. Always 'notification'.
          example: notification
        title:
          type: object
          description: >-
            Localized title keyed by language code (`en`, `sk`, `cs`, `de`). At
            least one locale required. Per-locale value is plain text, 1-60
            characters (Apple Wallet's lock-screen banner truncates around 60).
            Template variables are supported. Card-mechanics variables
            ({{card.balance}}, {{stamps_remaining}}, ...) require a card-scoped
            audience (card_ids).
          minProperties: 1
          additionalProperties:
            type: string
            minLength: 1
            maxLength: 60
          example:
            en: Summer special menu
        body:
          type: object
          description: >-
            Localized body keyed by language code (`en`, `sk`, `cs`, `de`). At
            least one locale required. Per-locale value is plain text, 1-240
            characters (worst-case room after banner chrome on Apple + Google).
            Template variables are supported. Card-mechanics variables
            ({{card.balance}}, {{stamps_remaining}}, ...) require a card-scoped
            audience (card_ids).
          minProperties: 1
          additionalProperties:
            type: string
            minLength: 1
            maxLength: 240
          example:
            en: Try the new lime lemonade for 2.50 EUR.
        audience:
          anyOf:
            - $ref: '#/components/schemas/NotificationAudience'
            - type: 'null'
          description: >-
            The audience filter this broadcast was sent with. Null/empty =
            broadcast to all active customers.
        status:
          type: string
          enum:
            - queued
            - scheduled
            - processing
            - completed
            - partial
            - failed
            - cancelled
          description: >-
            Broadcast lifecycle:

            - `queued` - accepted, fan-out imminent

            - `scheduled` - accepted with a future `schedule_at`; cancellable
            until it fires

            - `processing` - worker batches draining

            - `completed` - every per-recipient attempt finished (provider ack'd
            or retries exhausted; does NOT mean the human saw it)

            - `partial` - finished with failure rate above the warning threshold
            (~5%)

            - `failed` - catastrophic failure before deliveries (rare; safe to
            retry with a fresh Idempotency-Key). **Reserved: NOT emitted by v1
            today** (see note below).

            - `cancelled` - cancelled while queued/scheduled


            **`failed` is declared but NOT emitted by v1 today.** `status` is
            DERIVED per read from four raw signals (schedule flag + fire time,
            fan-out start, drain completion, delivery counters); nothing records
            a crash that happened before any delivery was attempted, so no code
            path can produce `failed`. `GET /v1/notifications?status=failed` is
            accepted and returns an empty page rather than an error, so
            branching over the full enum stays safe. The other six are all live,
            including `cancelled`, which is backed by a real `cancelledAt`
            timestamp set by `DELETE /v1/notifications/{id}` and takes
            precedence over every other signal.
          example: completed
        schedule_at:
          type:
            - integer
            - 'null'
          description: >-
            Unix seconds when a scheduled broadcast fires. Null for immediate
            sends. While in the future, the broadcast is normally `status:
            "scheduled"` and cancellable via DELETE. EXCEPTION: if the audience
            resolved to zero recipients at accept time there is nothing to
            deliver now or later, so the broadcast is accepted as already
            finished - `status` is `completed` with every counter at 0 and
            `audience_resolved_count: 0`, it never appears under
            `?status=scheduled`, and DELETE returns `409
            broadcast_not_cancellable` even though this value is still in the
            future. Poll on `status`, not on `schedule_at`.
          example: null
        sent_at:
          type:
            - integer
            - 'null'
          description: >-
            Unix seconds when fan-out started - set on EVERY send (immediate and
            scheduled). Null only before dispatch.
          example: 1782134401
        stats:
          $ref: '#/components/schemas/NotificationStats'
        created_at:
          type: integer
          description: Unix seconds. Time the broadcast was accepted.
          example: 1782134400
        completed_at:
          type:
            - integer
            - 'null'
          description: >-
            Unix seconds. Populated when status reaches `completed`, `partial`,
            or `failed`. Null while queued/processing.
          example: 1782134522
        request_id:
          type: string
          description: >-
            The request id of the request that ACCEPTED this broadcast. Include
            it in support requests: it identifies the exchange where the fan-out
            actually happened. On an idempotent replay (a repeat call with the
            same Idempotency-Key, answered with `Idempotent-Replayed: true`)
            this deliberately differs from the `Vexion-Request-Id` response
            header: the body keeps the original accept id, while the header
            carries the id of the replay exchange you are holding.
          example: req_01J9P0G7K9C0RYHXJ2K7A4N5MZ
    NotificationAudience:
      type: object
      description: >-
        Selects which customers receive the broadcast. Four optional id-array
        filters that compose as a logical **INTERSECTION (AND)** - never a
        union. Send an empty object `{}` (or omit `audience` entirely) to
        broadcast to every active customer in the calling organization that has
        at least one installed wallet pass.


        If you need a UNION, send separate broadcasts.
      properties:
        card_ids:
          type: array
          items:
            type: string
            pattern: ^crd_[A-Za-z0-9]+$
          minItems: 1
          maxItems: 50
          description: >-
            Limits the audience to customers holding one of the listed cards.
            1-50 `crd_` ids. Ids of another organization return `404
            not_found_error`.
          example:
            - crd_sophcrprtvpmmnwxah2lomnkee
        customer_ids:
          type: array
          items:
            type: string
            pattern: ^cus_[A-Za-z0-9]+$
          minItems: 1
          maxItems: 1000
          description: >-
            Direct cohort targeting. 1-1000 `cus_` ids. All ids must belong to
            the calling organization - an id of another organization fails the
            broadcast with `400 audience_invalid`. Ids resolving to a customer
            with no installed wallet pass are silently skipped (counted under
            neither delivered nor failed).
        external_ids:
          type: array
          items:
            type: string
          minItems: 1
          maxItems: 1000
          description: >-
            Merchant-side identifiers, 1-1000. Each resolves to a single `cus_`
            within the calling organization. Unknown external ids are silently
            skipped. If two customers share the same `external_id`
            (merchant-side data error), the broadcast fails with `422
            external_id_collision` so you can clean up before double-delivering.
          example:
            - loyalty-789
            - MEMBER-A23B-9942
        location_ids:
          type: array
          items:
            type: string
            pattern: ^loc_[A-Za-z0-9]+$
          minItems: 1
          maxItems: 25
          description: >-
            Target customers ATTRIBUTED to these locations - the location where
            they signed up or last visited. Combines with other audience keys as
            an intersection.
      example:
        card_ids:
          - crd_sophcrprtvpmmnwxah2lomnkee
    NotificationStats:
      type: object
      description: >-
        Aggregate delivery counters, updated as the asynchronous fan-out drains
        (queue → worker batches → per-device dispatch). Starts at zero on
        accept. For per-recipient rows, use `GET
        /v1/notifications/{id}/deliveries`.
      properties:
        total:
          type: integer
          description: Total resolved recipients across all channels.
          example: 142
        audience_resolved_count:
          type: integer
          description: >-
            Recipients that matched the audience after filtering (install filter
            + location attribution). Compare against your expected cohort size.
          example: 142
        apple_wallet:
          type: object
          description: >-
            Apple Wallet channel - APNs silent push; the device refetches the
            pass and iOS renders the changeMessage banner.
          properties:
            total:
              type: integer
              description: Recipients on this channel.
            delivered:
              type: integer
              description: Device-confirmed deliveries (pass re-fetch / API accept).
            failed:
              type: integer
              description: Terminal failures (stale tokens, uninstalled passes).
          example:
            total: 98
            delivered: 96
            failed: 2
        google_wallet:
          type: object
          description: Google Wallet channel - server-side object update + message.
          properties:
            total:
              type: integer
              description: Recipients on this channel.
            delivered:
              type: integer
              description: Device-confirmed deliveries (pass re-fetch / API accept).
            failed:
              type: integer
              description: Terminal failures.
          example:
            total: 23
            delivered: 22
            failed: 1
        delivered:
          type: integer
          description: Sum of delivered across channels.
          example: 138
        failed:
          type: integer
          description: Sum of failed across channels.
          example: 4
      example:
        total: 121
        audience_resolved_count: 121
        apple_wallet:
          total: 98
          delivered: 96
          failed: 2
        google_wallet:
          total: 23
          delivered: 22
          failed: 1
        delivered: 118
        failed: 3
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: >-
        Your secret API key as a Bearer token: `Authorization: Bearer
        vxn_sk_...`. Keys are created and scoped in the dashboard - see
        [Authentication](/api-reference/introduction#authentication).

````

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