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

# Reissue a reusable coupon

> Mass-reactivates a reusable coupon: every holder whose `couponstatus` is currently `redeemed` flips back to usable (the wallet pass QR reappears, the offer field renders again), and the refreshed pass content is pushed to every installed holder so the change is visible without asking anyone to reinstall. This is the API equivalent of the dashboard's coupon reissue action.

Scope: `cards:write`. `Idempotency-Key` required.

## Only a reusable coupon

Only works when `mechanics.is_reusable` is `true`. A single-use coupon exists specifically to be redeemed once per customer, so reissuing one would silently undo that guarantee: a non-reusable coupon (or any non-coupon card type) returns `422 coupon_not_reissuable`.

## Untouched holders stay untouched

A holder who never redeemed is left exactly as they were: they were already usable. `holders_reissued` in the response counts only the customers actually flipped from `redeemed` back to usable by THIS call.

## Counters always advance

`mechanics.reset_count` / `mechanics.last_reset_at` on the card (also returned inline as `reset_count` / `last_reset_at`) increment on every successful call, even when `holders_reissued` is `0`: the action ran, it simply had nothing to flip.

Fires `card.updated` (reset_count/last_reset_at are real, documented mechanics fields), exactly like `PATCH /v1/cards/{id}`.



## OpenAPI

````yaml /openapi.json post /v1/cards/{id}/reissue_coupons
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/cards/{id}/reissue_coupons:
    post:
      tags:
        - Cards
      summary: Reissue a reusable coupon
      description: >-
        Mass-reactivates a reusable coupon: every holder whose `couponstatus` is
        currently `redeemed` flips back to usable (the wallet pass QR reappears,
        the offer field renders again), and the refreshed pass content is pushed
        to every installed holder so the change is visible without asking anyone
        to reinstall. This is the API equivalent of the dashboard's coupon
        reissue action.


        Scope: `cards:write`. `Idempotency-Key` required.


        ## Only a reusable coupon


        Only works when `mechanics.is_reusable` is `true`. A single-use coupon
        exists specifically to be redeemed once per customer, so reissuing one
        would silently undo that guarantee: a non-reusable coupon (or any
        non-coupon card type) returns `422 coupon_not_reissuable`.


        ## Untouched holders stay untouched


        A holder who never redeemed is left exactly as they were: they were
        already usable. `holders_reissued` in the response counts only the
        customers actually flipped from `redeemed` back to usable by THIS call.


        ## Counters always advance


        `mechanics.reset_count` / `mechanics.last_reset_at` on the card (also
        returned inline as `reset_count` / `last_reset_at`) increment on every
        successful call, even when `holders_reissued` is `0`: the action ran, it
        simply had nothing to flip.


        Fires `card.updated` (reset_count/last_reset_at are real, documented
        mechanics fields), exactly like `PATCH /v1/cards/{id}`.
      operationId: reissueCoupons
      parameters:
        - name: id
          in: path
          required: true
          description: >-
            Card template identifier. Opaque, server-issued token, e.g.
            crd_c4zdlocdwajf6wtmnvvkonv4oa. Must reference a coupon card with
            mechanics.is_reusable=true.
          example: crd_sophcrprtvpmmnwxah2lomnkee
          schema:
            type: string
            pattern: ^crd_[A-Za-z0-9]+$
        - name: Idempotency-Key
          in: header
          required: true
          description: >-
            Required. Stable opaque string, 8-255 chars. Same key + same body
            within 24h replays the original response (Idempotent-Replayed:
            true); same key + different body -> 409 idempotency_key_conflict.
            See [Idempotency](/api-reference/idempotency).
          schema:
            type: string
            minLength: 8
            maxLength: 255
          example: reissue-9c1d6b00-2a3f-4f9c-8a6f-2e10b9e34c12
      responses:
        '200':
          description: >-
            Reissued. Returns how many holders were actually flipped back to
            usable, and the card's updated reset counters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CouponReissueResult'
              examples:
                Reissued with holders flipped:
                  summary: 138 redeemed holders reactivated
                  value:
                    object: coupon_reissue_result
                    card_id: crd_sophcrprtvpmmnwxah2lomnkee
                    holders_reissued: 138
                    reset_count: 4
                    last_reset_at: 1754035200
                Reissued with nothing to flip:
                  summary: No holder had redeemed yet, counters still advance
                  value:
                    object: coupon_reissue_result
                    card_id: crd_sophcrprtvpmmnwxah2lomnkee
                    holders_reissued: 0
                    reset_count: 1
                    last_reset_at: 1754035200
          headers: {}
        '400':
          description: Missing or malformed Idempotency-Key header.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  type: invalid_request_error
                  code: idempotency_key_required
                  message: >-
                    Idempotency-Key header is required on POST, PUT, PATCH, and
                    DELETE requests.
                  param: Idempotency-Key
                  doc_url: >-
                    https://vexioncards.mintlify.site/api-reference/errors#idempotency_key_required
                  request_id: req_01HW9Q3K2YJZ7M5RX1P8VTBNC4
          headers: {}
        '401':
          description: Missing, invalid, or revoked API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers: {}
        '403':
          description: >-
            API key lacks the cards:write scope, or the organization's account
            state (paused/locked/cancelled) blocks writes.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers: {}
        '404':
          description: No such card in your organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  type: not_found_error
                  code: resource_missing
                  message: No such card.
                  param: id
                  doc_url: >-
                    https://vexioncards.mintlify.site/api-reference/errors#resource_missing
                  request_id: req_01HW9Q3K2YJZ7M5RX1P8VTBNC4
          headers: {}
        '409':
          description: >-
            Idempotency-Key reuse: an earlier request with the same key is still
            processing, or was reused with a different body.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                Still processing:
                  summary: Concurrent retry
                  value:
                    error:
                      type: invalid_request_error
                      code: idempotency_key_in_use
                      message: >-
                        A request with this idempotency key is already being
                        processed. Retry shortly.
                      doc_url: >-
                        https://vexioncards.mintlify.site/api-reference/errors#idempotency_key_in_use
                      request_id: req_01HW9Q3K2YJZ7M5RX1P8VTBNC4
                Key reused with a different body:
                  summary: Same key, different request
                  value:
                    error:
                      type: idempotency_error
                      code: idempotency_key_conflict
                      message: >-
                        An idempotency key was reused with a different request
                        body. To retry safely, use a new idempotency key.
                      doc_url: >-
                        https://vexioncards.mintlify.site/api-reference/errors#idempotency_key_conflict
                      request_id: req_01HW9Q3K2YJZ7M5RX1P8VTBNC4
          headers: {}
        '422':
          description: >-
            The card is not a coupon, or is a single-use coupon
            (mechanics.is_reusable=false) that cannot be mass-reactivated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                Not a coupon:
                  summary: Card type is not coupon
                  value:
                    error:
                      type: invalid_request_error
                      code: coupon_not_reissuable
                      message: >-
                        Only a coupon card can be reissued. This card is type
                        'reward'.
                      param: id
                      doc_url: >-
                        https://vexioncards.mintlify.site/api-reference/errors#coupon_not_reissuable
                      request_id: req_01HW9Q3K2YJZ7M5RX1P8VTBNC4
                Not reusable:
                  summary: Single-use coupon
                  value:
                    error:
                      type: invalid_request_error
                      code: coupon_not_reissuable
                      message: >-
                        This coupon is not reusable
                        (mechanics.is_reusable=false), it is single-use per
                        customer and reissuing it would silently undo that
                        guarantee. Set is_reusable=true via PATCH first if that
                        was not intentional.
                      param: id
                      doc_url: >-
                        https://vexioncards.mintlify.site/api-reference/errors#coupon_not_reissuable
                      request_id: req_01HW9Q3K2YJZ7M5RX1P8VTBNC4
          headers: {}
        '429':
          description: Per-minute or per-day rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers: {}
        '500':
          description: Server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers: {}
      deprecated: false
      x-codeSamples:
        - lang: curl
          label: cURL
          source: >-
            curl -X POST
            https://api.vexioncards.one/v1/cards/crd_sophcrprtvpmmnwxah2lomnkee/reissue_coupons
            \
              -H "Authorization: Bearer $VXN_API_KEY" \
              -H "Idempotency-Key: $(uuidgen)"
        - lang: javascript
          label: Node.js
          source: >-
            const result = await (await fetch(
              'https://api.vexioncards.one/v1/cards/crd_sophcrprtvpmmnwxah2lomnkee/reissue_coupons',
              {
                method: 'POST',
                headers: {
                  Authorization: `Bearer ${process.env.VXN_API_KEY}`,
                  'Idempotency-Key': crypto.randomUUID(),
                },
              }
            )).json();

            console.log(`Reissued to ${result.holders_reissued} holders (reset
            #${result.reset_count})`);
        - lang: python
          label: Python
          source: >-
            import os, uuid, requests

            result = requests.post(
                "https://api.vexioncards.one/v1/cards/crd_sophcrprtvpmmnwxah2lomnkee/reissue_coupons",
                headers={
                    "Authorization": f"Bearer {os.environ['VXN_API_KEY']}",
                    "Idempotency-Key": str(uuid.uuid4()),
                },
            ).json()

            print(f"Reissued to {result['holders_reissued']} holders (reset
            #{result['reset_count']})")
components:
  schemas:
    CouponReissueResult:
      type: object
      description: >-
        Result of POST /v1/cards/{id}/reissue_coupons: how many holders were
        actually flipped back to usable, plus the card's updated reset counters.
      required:
        - object
        - card_id
        - holders_reissued
        - reset_count
        - last_reset_at
      properties:
        object:
          type: string
          const: coupon_reissue_result
        card_id:
          type: string
          description: >-
            The reissued card. Opaque, server-issued token, e.g.
            crd_c4zdlocdwajf6wtmnvvkonv4oa.
          example: crd_sophcrprtvpmmnwxah2lomnkee
        holders_reissued:
          type: integer
          minimum: 0
          description: >-
            Number of customers whose couponstatus was actually flipped from
            redeemed back to usable by THIS call. A customer who never redeemed
            was already usable and is not counted.
          example: 138
        reset_count:
          type: integer
          minimum: 0
          description: >-
            The card's mechanics.reset_count AFTER this call (same value a
            subsequent GET /v1/cards/{id} reports). Increments on every call,
            even when holders_reissued is 0.
          example: 4
        last_reset_at:
          type:
            - integer
            - 'null'
          description: >-
            Unix timestamp of this reissue (same as the card's
            mechanics.last_reset_at after this call).
          example: 1754035200
    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.
  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.