> ## 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 webhook endpoints

> Lists your registered webhook receivers, cursor-paginated (default 25, max 100), newest first. Filter by `status` to find `auto_disabled` endpoints that need attention after sustained failures.

The `secret` is never included - it exists only in the create and rotate responses. See [Webhooks](/api-reference/webhooks) for the delivery contract, signature verification, and retry schedule.

Scope: `webhooks:read`.



## OpenAPI

````yaml /openapi.json get /v1/webhook_endpoints
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/webhook_endpoints:
    get:
      tags:
        - Webhook endpoints
      summary: List webhook endpoints
      description: >-
        Lists your registered webhook receivers, cursor-paginated (default 25,
        max 100), newest first. Filter by `status` to find `auto_disabled`
        endpoints that need attention after sustained failures.


        The `secret` is never included - it exists only in the create and rotate
        responses. See [Webhooks](/api-reference/webhooks) for the delivery
        contract, signature verification, and retry schedule.


        Scope: `webhooks:read`.
      operationId: listWebhookEndpoints
      parameters:
        - name: status
          in: query
          description: Filter by endpoint status (`enabled`, `disabled`, `auto_disabled`).
          required: false
          schema:
            type: string
            enum:
              - enabled
              - disabled
              - auto_disabled
        - name: limit
          in: query
          required: false
          description: Page size, 1-100. Default 25.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
        - name: starting_after
          in: query
          description: >-
            Walk forward. Send the last id from the previous page's data[].
            Numeric offset or page parameters are not supported; cursors are the
            only supported paging mechanism.
          required: false
          schema:
            type: string
        - name: ending_before
          in: query
          description: Walk backward. Send the first id from the current page's data[].
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Paginated webhook endpoint list.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpointList'
              examples:
                Endpoints:
                  summary: Two registered receivers
                  value:
                    object: list
                    data:
                      - id: whk_01HW9RBZ4GH7N8MTX1RVWHKDEF
                        object: webhook_endpoint
                        url: https://hooks.demo-coffee.example/vexion
                        description: Loyalty events to ERP
                        enabled_events:
                          - customer.created
                          - customer.pass_installed
                          - transaction.created
                        status: enabled
                        consecutive_failures: 0
                        api_version: 2026-07
                        created_at: 1750691700
                        updated_at: 1750691700
                      - id: whk_01HW9RBZ4GH7N8MTX1RVWHKMAG
                        object: webhook_endpoint
                        url: https://hooks.demo-salon.example/vexion
                        description: null
                        enabled_events:
                          - customer.created
                          - transaction.created
                        status: enabled
                        consecutive_failures: 7
                        api_version: 2026-07
                        created_at: 1750691700
                        updated_at: 1750691700
                    has_more: false
                    url: /v1/webhook_endpoints
          headers: {}
        '400':
          description: >-
            Invalid pagination parameter: limit outside 1-100, or a malformed
            cursor.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                Invalid limit:
                  summary: limit out of range
                  value:
                    error:
                      type: invalid_request_error
                      code: invalid_limit
                      message: limit must be an integer between 1 and 100.
                      doc_url: >-
                        https://vexioncards.mintlify.site/api-reference/errors#invalid_limit
                      request_id: req_5f8b2c4a9e1d3
                      param: limit
                Malformed cursor:
                  summary: starting_after is not a valid cursor
                  value:
                    error:
                      type: invalid_request_error
                      code: invalid_cursor
                      message: starting_after is not a valid cf_ cursor.
                      doc_url: >-
                        https://vexioncards.mintlify.site/api-reference/errors#invalid_cursor
                      request_id: req_5f8b2c4a9e1d3
                      param: starting_after
          headers: {}
        '401':
          description: Missing, invalid, or revoked API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Key lacks the required scope (webhooks:read).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limited - respect Retry-After.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Server error. Retry-safe on idempotent calls.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  type: api_error
                  code: internal_error
                  message: >-
                    An internal error occurred. The request may be retried with
                    the same Idempotency-Key.
                  doc_url: >-
                    https://vexioncards.mintlify.site/api-reference/errors#internal_error
                  request_id: req_5f8b2c4a9e1d3
              examples:
                Http 500 default:
                  summary: Http 500 default
                  value:
                    error:
                      type: api_error
                      code: internal_error
                      message: >-
                        An internal error occurred. The request may be retried
                        with the same Idempotency-Key.
                      doc_url: >-
                        https://vexioncards.mintlify.site/api-reference/errors#internal_error
                      request_id: req_5f8b2c4a9e1d3
          headers: {}
      deprecated: false
components:
  schemas:
    WebhookEndpointList:
      allOf:
        - $ref: '#/components/schemas/ListEnvelope'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/WebhookEndpoint'
    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.
    ListEnvelope:
      type: object
      required:
        - object
        - data
        - has_more
      properties:
        object:
          type: string
          const: 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 - pass the last item id as
            `starting_after`.
        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 for list endpoints. See the
        Pagination guide.
    WebhookEndpoint:
      type: object
      description: >-
        A registered outbound webhook receiver. Each endpoint is independently
        scoped (event subscription list), secured (own HMAC secret), paused, and
        monitored. The `secret` is NEVER present on GET - it is returned exactly
        once by create and rotate.
      required:
        - id
        - object
        - url
        - enabled_events
        - status
        - consecutive_failures
        - api_version
        - created_at
      properties:
        id:
          type: string
          pattern: ^whk_[A-Za-z0-9]+$
          description: >-
            Endpoint identifier, `whk_` prefixed opaque string. Never a database
            id.
          example: whk_01HW9RBZ4GH7N8MTX1RVWHKDEF
        object:
          type: string
          const: webhook_endpoint
          description: Always `"webhook_endpoint"`.
        url:
          type: string
          format: uri
          description: >-
            HTTPS URL we POST events to. Validated against SSRF rules at
            registration AND re-validated per delivery attempt (DNS rebinding
            defense: every attempt re-resolves and re-checks the IP against the
            blocklist - no private ranges, no cloud metadata endpoints, no
            localhost).
          example: https://hooks.demo-coffee.example/vexion
        description:
          type:
            - string
            - 'null'
          maxLength: 200
          description: Free-text merchant-facing label. Optional.
          example: Loyalty events to ERP
        enabled_events:
          type: array
          items:
            $ref: '#/components/schemas/WebhookEventSubscription'
          description: >-
            Explicit array of event names from the 22-event catalog. The
            wildcard `["*"]` subscribes to every current AND future event - we
            recommend explicit names so a new event does not surprise your
            receiver.
          example:
            - customer.created
            - customer.pass_installed
            - transaction.created
        status:
          type: string
          enum:
            - enabled
            - disabled
            - auto_disabled
          description: >-
            `enabled`/`disabled` are merchant-toggled. `auto_disabled` is set by
            the platform after 50 consecutive failures OR a single 410 Gone
            response - requires explicit re-enable (dashboard or PATCH with
            `status: "enabled"`), forcing investigation before more events flow.
          example: enabled
        consecutive_failures:
          type: integer
          minimum: 0
          description: >-
            Consecutive FAILED delivery attempts across every event to this
            endpoint, reset to 0 on any successful delivery. The platform
            auto-disables the endpoint (`status` flips to `auto_disabled`) once
            this reaches **50**, OR instantly on a single `410 Gone` response
            regardless of this count. Watch this to alert before auto-disable
            happens rather than after.
          example: 0
        api_version:
          type: string
          description: >-
            Date-based API version all event payloads to this endpoint serialize
            against - pinned at creation, **immutable** (a live consumer's
            payload shape never changes under it). The platform launches on
            `2026-07`; when a new version ships, upgrade with zero downtime:
            create a second endpoint on the new version, verify with the test
            endpoint, cut your consumer over, delete the old one.
          example: 2026-07
        created_at:
          type: integer
          description: Unix seconds.
          example: 1750691700
        updated_at:
          type: integer
          description: Unix seconds of last change.
          example: 1750691700
    WebhookEventSubscription:
      description: >-
        What an endpoint SUBSCRIBES to: either one of the 22 catalog event
        names, or the wildcard `*` meaning every event, current and future.


        This is deliberately distinct from `WebhookEventName`. A DELIVERED event
        always carries a concrete name, so `*` is never valid as
        `WebhookEvent.type`, `WebhookDelivery.event_type`, the `event_type` you
        send to `POST /v1/webhook_endpoints/{id}/test`, or the `event_type`
        filter on the deliveries list. It is valid ONLY inside `enabled_events`.


        `*` must be sent alone: `["*", "customer.created"]` returns `422
        validation_failed`.
      anyOf:
        - $ref: '#/components/schemas/WebhookEventName'
        - const: '*'
          title: All events (current and future)
      example: customer.created
    WebhookEventName:
      type: string
      enum:
        - customer.created
        - customer.updated
        - customer.deleted
        - customer.pass_installed
        - customer.pass_uninstalled
        - card.created
        - card.updated
        - card.deleted
        - custom_field.created
        - custom_field.updated
        - custom_field.deleted
        - product.created
        - product.updated
        - transaction.created
        - transaction.reversed
        - notification.sent
        - notification.delivery_updated
        - location.updated
        - team_member.added
        - team_member.updated
        - team_member.removed
        - webhook_endpoint.delivery_failed
      description: >-
        The locked v1 event catalog - 22 events across 9 subjects. Names follow
        `resource.action` with past-participle actions (`transaction.created`),
        never the dotted verb-stems used by transaction types - the two
        vocabularies never mix. `product.created`/`product.updated` fire for
        dashboard and API-created catalog changes; POS-synced catalog changes do
        not emit (they mirror the till, and a first sync would flood your
        endpoint).
      example: transaction.created
  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.