Lightspark Cards API

Card management endpoints. Issue debit cards against an internal account, freeze / unfreeze, close, manage card funding sources, and list card transactions.

Operations 5

POST /cards Issue a card #
GET /cards List cards #
GET /cards/{id} Get a card #
PATCH /cards/{id} Update a card #
POST /cards/{id}/reveal Reveal card details #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/lightspark-cards-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

lightspark-cards-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Grid Cards API
  description: 'API for managing global payments on the open Money Grid. Built by Lightspark. See the full documentation at https://docs.lightspark.com/.

    '
  version: '2025-10-13'
  contact:
    name: Lightspark Support
    email: support@lightspark.com
  license:
    name: Proprietary
    url: https://lightspark.com/terms
servers:
- url: https://api.lightspark.com/grid/2025-10-13
  description: Production server
security:
- BasicAuth: []
- AgentAuth: []
tags:
- name: Cards
  description: Card management endpoints. Issue debit cards against an internal account, freeze / unfreeze, close, manage card funding sources, and list card transactions.
paths:
  /cards:
    post:
      summary: Issue a card
      description: 'Issue a new card for a cardholder. Every card must be bound to at least one funding source at create time. The cardholder must have KYC status `APPROVED` before a card can be issued; otherwise the request is rejected with `CARDHOLDER_KYC_NOT_APPROVED`.


        If any funding source is an Embedded Wallet internal account, the cardholder must authorize Grid to sign Spark token transactions for that card funding source by completing the delegated-key creation flow with `POST /auth/delegated-keys`. Until an active delegated key exists for that funding source, Authorization Decisioning cannot use it to fund card transactions.


        New cards start in `state: "PROCESSING"` while the card issuer provisions the card. The `card.state_change` webhook fires on each state transition, including the transition to `ACTIVE` (or to `CLOSED` with `stateReason: "ISSUER_REJECTED"` if provisioning fails).

        '
      operationId: createCard
      tags:
      - Cards
      security:
      - BasicAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CardCreateRequest'
            examples:
              virtualCard:
                summary: Issue a virtual card with one funding source
                value:
                  cardholderId: Customer:019542f5-b3e7-1d02-0000-000000000001
                  platformCardId: card-emp-aary-001
                  form: VIRTUAL
                  fundingSources:
                  - InternalAccount:019542f5-b3e7-1d02-0000-000000000002
      responses:
        '201':
          description: Card created successfully. Newly-created cards start in `PROCESSING` while the issuer provisions them. Cards funded by an Embedded Wallet internal account also require an active delegated key for that funding source before Authorization Decisioning can use it.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Card'
        '400':
          description: Bad request. Returned with `CARDHOLDER_KYC_NOT_APPROVED` when the cardholder's KYC status is not `APPROVED`, with `FUNDING_SOURCE_INELIGIBLE` when the supplied funding source does not belong to the cardholder or is not denominated in a card-eligible currency, and for general invalid parameters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error400'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error401'
        '500':
          description: Internal service error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error500'
        '501':
          description: Not implemented in this environment. Card issuance is not enabled for every Grid deployment; environments without a configured card issuer return `501 NOT_IMPLEMENTED`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error501'
    get:
      summary: List cards
      description: 'Retrieve a paginated list of cards. Cards can be filtered by cardholder, bound funding-source internal account, state, and platform-specific card identifier. If no filters are provided, returns all cards visible to the caller.

        '
      operationId: listCards
      tags:
      - Cards
      security:
      - BasicAuth: []
      parameters:
      - name: cardholderId
        in: query
        description: Filter by cardholder (customer) id.
        required: false
        schema:
          type: string
      - name: accountId
        in: query
        description: Filter by internal account id. Returns cards whose `fundingSources` array contains the given internal account id.
        required: false
        schema:
          type: string
      - name: platformCardId
        in: query
        description: Filter by platform-specific card identifier.
        required: false
        schema:
          type: string
      - name: state
        in: query
        description: Filter by card state.
        required: false
        schema:
          $ref: '#/components/schemas/CardState'
      - name: limit
        in: query
        description: Maximum number of results to return (default 20, max 100)
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 20
      - name: cursor
        in: query
        description: Cursor for pagination (returned from previous request)
        required: false
        schema:
          type: string
      - name: sortOrder
        in: query
        description: Order to sort results in
        required: false
        schema:
          type: string
          enum:
          - asc
          - desc
          default: desc
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CardListResponse'
        '400':
          description: Bad request - Invalid parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error400'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error401'
        '500':
          description: Internal service error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error500'
        '501':
          description: Not implemented in this environment. Cards are not enabled for every Grid deployment; environments without a configured card issuer return `501 NOT_IMPLEMENTED`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error501'
  /cards/{id}:
    parameters:
    - name: id
      in: path
      description: System-generated unique card identifier
      required: true
      schema:
        type: string
    get:
      summary: Get a card
      description: Retrieve a card by its system-generated id. To display the card's full PAN, CVV, and expiry to the cardholder, request a reveal with `POST /cards/{id}/reveal` — the card resource itself never carries the reveal URL.
      operationId: getCardById
      tags:
      - Cards
      security:
      - BasicAuth: []
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Card'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error401'
        '404':
          description: Card not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error404'
        '500':
          description: Internal service error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error500'
        '501':
          description: Not implemented in this environment. Cards are not enabled for every Grid deployment; environments without a configured card issuer return `501 NOT_IMPLEMENTED`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error501'
    patch:
      summary: Update a card
      description: 'Update a card''s `state` and / or its bound `fundingSources`. At least one of the two fields must be supplied.


        - `state` transitions are limited to `ACTIVE ⇄ FROZEN` and `ACTIVE | FROZEN → CLOSED`. `CLOSED` is terminal and irreversible. Any other transition returns `409 INVALID_STATE_TRANSITION`.

        - `fundingSources`, when supplied, fully replaces the card''s bound funding sources. Array order determines the priority Authorization Decisioning tries them in. Each id must belong to the cardholder and be denominated in the card''s currency; the list must contain at least one source. `fundingSources` cannot be supplied alongside `state: CLOSED`.


        Because both updates are sensitive state changes, this endpoint uses Grid''s 202 → signed-retry pattern (same shape as `DELETE /auth/credentials/{id}` and `POST /internal-accounts/{id}/export`):


        1. Call `PATCH /cards/{id}` with the target fields and no signing headers. The response is `202` with a `payloadToSign`, `requestId`, and `expiresAt`.


        2. Sign the `payloadToSign` with the session private key of a verified authentication credential on the card''s owning internal account and retry with the signature as the `Grid-Wallet-Signature` header and the `requestId` echoed back as the `Request-Id` header. The signed retry returns `200` with the updated `Card`.


        Effects:

        - `state: FROZEN`: Authorization Decisioning declines new auths with `CARD_PAUSED`. Existing pulls and in-flight reconciliation continue — freezing does not pause the lifecycle of authorizations that already passed.

        - `state: ACTIVE`: normal authorization behavior resumes.

        - `state: CLOSED`: terminal close. The card transitions to `state: "CLOSED"` with `stateReason: "CLOSED_BY_PLATFORM"` and stays in the system for audit and reconciliation. All pending auths reconcile to a terminal state via the existing reconcile primitive. Inbound clearings received after close follow the standard force-post / late-presentment path — Lightspark absorbs the loss if a post-hoc pull on the now-unbound source fails. Funding-source bindings are detached. Refunds already in flight still complete because Lightspark holds the card-reserve keys.

        - `fundingSources` change: emits `card.funding_source_change` reflecting the new ordered binding.


        The `card.state_change` webhook fires on every successful `state` transition; the `card.funding_source_change` webhook fires whenever `fundingSources` is updated.

        '
      operationId: updateCardById
      tags:
      - Cards
      security:
      - BasicAuth: []
      parameters:
      - name: Grid-Wallet-Signature
        in: header
        required: false
        description: Signature over the `payloadToSign` returned in a prior `202` response, produced with the session private key of a verified authentication credential on the card's owning internal account and base64-encoded. Required on the signed retry; ignored on the initial call.
        schema:
          type: string
        example: MEUCIQDx7k2N0aK4p8f3vR9J6yT5wL1mB0sXnG2hQ4vJ8zYkCgIgZ4rP9dT7eWfU3oM6KjR1qSpNvBwL0tXyA2iG8fH5dE=
      - name: Request-Id
        in: header
        required: false
        description: The `requestId` returned in a prior `202` response, echoed back on the signed retry so the server can correlate it with the issued challenge. Required on the signed retry; must be paired with `Grid-Wallet-Signature`.
        schema:
          type: string
        example: 7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CardUpdateRequest'
            examples:
              freeze:
                summary: Freeze an active card
                value:
                  state: FROZEN
              unfreeze:
                summary: Unfreeze a frozen card
                value:
                  state: ACTIVE
              updateFundingSources:
                summary: Replace the card's bound funding sources
                value:
                  fundingSources:
                  - InternalAccount:019542f5-b3e7-1d02-0000-000000000002
                  - InternalAccount:019542f5-b3e7-1d02-0000-000000000003
              freezeAndUpdateSources:
                summary: Freeze the card and replace its funding sources in one call
                value:
                  state: FROZEN
                  fundingSources:
                  - InternalAccount:019542f5-b3e7-1d02-0000-000000000002
              close:
                summary: Permanently close the card
                value:
                  state: CLOSED
      responses:
        '200':
          description: Signed retry accepted. Returns the updated card.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Card'
        '202':
          description: Challenge issued. The response contains a `payloadToSign` that must be signed with the session private key of a verified authentication credential on the card's owning internal account, along with a `requestId` that must be echoed back on the retry.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SignedRequestChallenge'
        '400':
          description: Bad request. Returned with `FUNDING_SOURCE_INELIGIBLE` when a supplied funding source does not belong to the cardholder or is not denominated in the card's currency, and for general invalid parameters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error400'
        '401':
          description: Unauthorized. Returned when the provided `Grid-Wallet-Signature` is missing, malformed, or does not match a pending update challenge for this card, or when the `Request-Id` does not match an unexpired pending challenge.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error401'
        '404':
          description: Card not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error404'
        '409':
          description: 'Conflict. Returned with `INVALID_STATE_TRANSITION` when the requested `state` transition is not one of `ACTIVE ⇄ FROZEN` or `ACTIVE | FROZEN → CLOSED` (e.g. trying to un-freeze a `CLOSED` card); with `CARD_ALREADY_CLOSED` when `state: CLOSED` is requested for a card that is already `CLOSED`; and with `CARD_NOT_MUTABLE` when the card is `CLOSED`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error409'
        '500':
          description: Internal service error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error500'
        '501':
          description: Not implemented in this environment. Cards are not enabled for every Grid deployment; environments without a configured card issuer return `501 NOT_IMPLEMENTED`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error501'
  /cards/{id}/reveal:
    parameters:
    - name: id
      in: path
      description: System-generated unique card identifier
      required: true
      schema:
        type: string
    post:
      summary: Reveal card details
      description: 'Mint a signed, short-lived URL for the card processor''s iframe that displays the card''s full PAN, CVV, and expiry to the cardholder. This is the only way to obtain a reveal URL — the `Card` resource never carries one.


        Request the reveal right before rendering the iframe and render the returned `panEmbedUrl` immediately; it expires at `expiresAt` (within minutes). Never store, cache, or log the URL — it is a bearer secret for the full card details. The card data renders inside the processor''s iframe and never crosses Grid''s or your servers.


        Every reveal is audit-logged with the requesting actor.'
      operationId: revealCard
      tags:
      - Cards
      security:
      - BasicAuth: []
      responses:
        '200':
          description: Reveal URL minted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CardRevealResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error401'
        '403':
          description: Forbidden. The session has no attributable actor to audit the reveal against (for example, an impersonated dashboard session).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error403'
        '404':
          description: Card not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error404'
        '500':
          description: Internal service error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error500'
        '501':
          description: Not implemented in this environment. Cards are not enabled for every Grid deployment; environments without a configured card issuer return `501 NOT_IMPLEMENTED`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error501'
components:
  schemas:
    CardStateReason:
      type: string
      enum:
      - ISSUER_REJECTED
      - CLOSED_BY_PLATFORM
      - CLOSED_BY_GRID
      description: 'Reason a card reached a terminal or non-active state. Present on

        `CLOSED` cards, and on cards that fail provisioning before reaching

        `ACTIVE`.


        | Reason | Description |

        |--------|-------------|

        | `ISSUER_REJECTED` | The card issuer rejected provisioning during `PROCESSING`. |

        | `CLOSED_BY_PLATFORM` | The card was closed via `PATCH /cards/{id}` (`state: CLOSED`) by the platform. |

        | `CLOSED_BY_GRID` | The card was closed by Grid (e.g. compliance or risk action). |

        '
    SignedRequestChallenge:
      title: Signed Request Challenge
      type: object
      required:
      - payloadToSign
      - requestId
      - expiresAt
      description: Common base for two-step signed-retry challenge responses on Embedded Wallet endpoints (credential registration or revocation, session refresh or revocation, wallet export, customer email updates, and similar). Holds the signing fields shared across every challenge shape; each variant composes this base via `allOf` and adds its own resource `id` (and `type`, when applicable) with variant-specific description and example.
      properties:
        payloadToSign:
          type: string
          description: Canonical payload for the retry authorization stamp. Build an API-key stamp over this exact value with the session API keypair, then send the full base64url-encoded stamp in `Grid-Wallet-Signature` on the retry that completes the original request.
          example: '{"organizationId":"org_2m9F...","parameters":{"userId":"user_2m9F..."},"timestampMs":"1775681700000","type":"ACTIVITY_TYPE_EXAMPLE"}'
        requestId:
          type: string
          description: Grid-issued `Request:<uuid>` identifier for this pending request. Echo this value exactly in the `Request-Id` header on the signed retry so the server can correlate the retry with the issued challenge.
          example: Request:7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21
        expiresAt:
          type: string
          format: date-time
          description: Timestamp after which this challenge is no longer valid. The signed retry must be submitted before this time.
          example: '2026-04-08T15:35:00Z'
    Error400:
      type: object
      required:
      - message
      - status
      - code
      properties:
        status:
          type: integer
          enum:
          - 400
          description: HTTP status code
        code:
          type: string
          description: '| Error Code | Description |

            |------------|-------------|

            | INVALID_INPUT | Invalid input provided |

            | MISSING_MANDATORY_USER_INFO | Required customer information is missing |

            | INVITATION_ALREADY_CLAIMED | Invitation has already been claimed |

            | INVITATIONS_NOT_CONFIGURED | Invitations are not configured |

            | INVALID_UMA_ADDRESS | UMA address format is invalid |

            | INVITATION_CANCELLED | Invitation has been cancelled |

            | QUOTE_REQUEST_FAILED | An issue occurred during the quote process; this is retryable |

            | INVALID_PAYREQ_RESPONSE | Counterparty Payreq response was invalid |

            | INVALID_RECEIVER | Receiver is invalid |

            | PARSE_PAYREQ_RESPONSE_ERROR | Error parsing receiver PayReq response |

            | CERT_CHAIN_INVALID | Counterparty certificate chain is invalid |

            | CERT_CHAIN_EXPIRED | Counterparty certificate chain has expired |

            | INVALID_PUBKEY_FORMAT | Counterparty Public key format is invalid |

            | MISSING_REQUIRED_UMA_PARAMETERS | Counterparty required UMA parameters are missing |

            | SENDER_NOT_ACCEPTED | Sender is not accepted |

            | AMOUNT_OUT_OF_RANGE | Amount is out of range |

            | INVALID_CURRENCY | Currency is invalid |

            | INVALID_TIMESTAMP | Timestamp is invalid |

            | INVALID_NONCE | Nonce is invalid |

            | INVALID_REQUEST_FORMAT | Request format is invalid |

            | INVALID_BANK_ACCOUNT | Bank account is invalid |

            | SELF_PAYMENT | Self payment not allowed |

            | LOOKUP_REQUEST_FAILED | Lookup request failed |

            | PARSE_LNURLP_RESPONSE_ERROR | Error parsing LNURLP response |

            | INVALID_AMOUNT | Amount is invalid |

            | WEBHOOK_ENDPOINT_NOT_SET | Webhook endpoint is not set |

            | WEBHOOK_DELIVERY_ERROR | Webhook delivery error |

            | LOW_QUALITY | Document quality too low to process |

            | DATA_MISMATCH | Document details don''t match provided information |

            | EXPIRED | Document has expired |

            | SUSPECTED_FRAUD | Document suspected of being forged or edited |

            | UNSUITABLE_DOCUMENT | Document type is not accepted or not supported |

            | INCOMPLETE | Document is missing pages or sides |

            | EMAIL_OTP_CREDENTIAL_ALREADY_EXISTS | An EMAIL_OTP credential is already registered on the target internal account; only one email OTP credential is supported per internal account at this time |

            | SMS_OTP_CREDENTIAL_ALREADY_EXISTS | An SMS_OTP credential is already registered on the target internal account; only one SMS OTP credential is supported per internal account at this time |

            | PASSKEY_CREDENTIAL_ALREADY_EXISTS | A PASSKEY credential with the same WebAuthn credentialId is already registered on the target internal account |

            | STABLECOIN_PROVIDER_ACCOUNT_INVALID | The stablecoin provider account link is not usable |

            | STABLECOIN_PROVIDER_ACCOUNT_REVOKED | The stablecoin provider account link has been revoked |

            | STABLECOIN_PROVIDER_ACCOUNT_SELECTION_REQUIRED | Multiple active provider account links exist; pass `stablecoinProviderAccountId` to select one |

            '
          enum:
          - INVALID_INPUT
          - MISSING_MANDATORY_USER_INFO
          - INVITATION_ALREADY_CLAIMED
          - INVITATIONS_NOT_CONFIGURED
          - INVALID_UMA_ADDRESS
          - INVITATION_CANCELLED
          - QUOTE_REQUEST_FAILED
          - INVALID_PAYREQ_RESPONSE
          - INVALID_RECEIVER
          - PARSE_PAYREQ_RESPONSE_ERROR
          - CERT_CHAIN_INVALID
          - CERT_CHAIN_EXPIRED
          - INVALID_PUBKEY_FORMAT
          - MISSING_REQUIRED_UMA_PARAMETERS
          - SENDER_NOT_ACCEPTED
          - AMOUNT_OUT_OF_RANGE
          - INVALID_CURRENCY
          - INVALID_TIMESTAMP
          - INVALID_NONCE
          - INVALID_REQUEST_FORMAT
          - INVALID_BANK_ACCOUNT
          - SELF_PAYMENT
          - LOOKUP_REQUEST_FAILED
          - PARSE_LNURLP_RESPONSE_ERROR
          - INVALID_AMOUNT
          - WEBHOOK_ENDPOINT_NOT_SET
          - WEBHOOK_DELIVERY_ERROR
          - LOW_QUALITY
          - DATA_MISMATCH
          - EXPIRED
          - SUSPECTED_FRAUD
          - UNSUITABLE_DOCUMENT
          - INCOMPLETE
          - EMAIL_OTP_CREDENTIAL_ALREADY_EXISTS
          - SMS_OTP_CREDENTIAL_ALREADY_EXISTS
          - PASSKEY_CREDENTIAL_ALREADY_EXISTS
          - STABLECOIN_PROVIDER_ACCOUNT_INVALID
          - STABLECOIN_PROVIDER_ACCOUNT_REVOKED
          - STABLECOIN_PROVIDER_ACCOUNT_SELECTION_REQUIRED
        message:
          type: string
          description: Error message
        details:
          type: object
          description: Additional error details
          additionalProperties: true
    CardRevealResponse:
      type: object
      required:
      - panEmbedUrl
      - expiresAt
      properties:
        panEmbedUrl:
          type: string
          format: uri
          description: 'Signed URL of the card processor''s iframe that securely displays the PAN, CVV, and expiry to the cardholder. The full PAN and CVV never cross Grid''s servers — render this URL in an iframe in your client to reveal card details. The URL is a short-lived bearer secret: render it immediately and never store, cache, or log it.'
          example: https://embed.lithic.com/iframe/...?t=...
        expiresAt:
          type: string
          format: date-time
          description: When the signed URL stops loading. Request a new reveal rather than re-rendering an expired URL.
          example: '2026-05-08T14:16:00Z'
    CardForm:
      type: string
      enum:
      - VIRTUAL
      description: 'Physical form factor of the card. Only `VIRTUAL` is supported in v1;

        `PHYSICAL` will be added in a later release.

        '
    Error500:
      type: object
      required:
      - message
      - status
      - code
      properties:
        status:
          type: integer
          enum:
          - 500
          description: HTTP status code
        code:
          type: string
          description: '| Error Code | Description |

            |------------|-------------|

            | GRID_SWITCH_ERROR | Grid switch error |

            | INTERNAL_ERROR | Internal server or UMA error |

            '
          enum:
          - GRID_SWITCH_ERROR
          - INTERNAL_ERROR
        message:
          type: string
          description: Error message
        details:
          type: object
          description: Additional error details
          additionalProperties: true
    Error403:
      type: object
      required:
      - message
      - status
      - code
      properties:
        status:
          type: integer
          enum:
          - 403
          description: HTTP status code
        code:
          type: string
          description: '| Error Code | Description |

            |------------|-------------|

            | FORBIDDEN | Insufficient permissions |

            | USER_NOT_READY | Customer exists but is not ready for operation |

            | COUNTERPARTY_NOT_ALLOWED | Counterparty has not been enabled for your account |

            | VELOCITY_LIMIT_EXCEEDED | Counterparty has exceeded velocity limits |

            '
          enum:
          - FORBIDDEN
          - USER_NOT_READY
          - COUNTERPARTY_NOT_ALLOWED
          - VELOCITY_LIMIT_EXCEEDED
        message:
          type: string
          description: Error message
        details:
          type: object
          description: Additional error details
          additionalProperties: true
    Error404:
      type: object
      required:
      - message
      - status
      - code
      properties:
        status:
          type: integer
          enum:
          - 404
          description: HTTP status code
        code:
          type: string
          description: '| Error Code | Description |

            |------------|-------------|

            | TRANSACTION_NOT_FOUND | Transaction not found |

            | INVITATION_NOT_FOUND | Invitation not found |

            | USER_NOT_FOUND | Customer not found |

            | QUOTE_NOT_FOUND | Quote not found |

            | LOOKUP_REQUEST_NOT_FOUND | Lookup request not found |

            | TOKEN_NOT_FOUND | Token not found |

            | BULK_UPLOAD_JOB_NOT_FOUND | Bulk upload job not found |

            | REFERENCE_NOT_FOUND | Reference not found |

            | UMA_NOT_FOUND | The UMA address is well-formed but no receiver exists at the counterparty VASP |

            | STABLECOIN_PROVIDER_ACCOUNT_NOT_FOUND | Stablecoin provider account link not found |

            '
          enum:
          - TRANSACTION_NOT_FOUND
          - INVITATION_NOT_FOUND
          - USER_NOT_FOUND
          - QUOTE_NOT_FOUND
          - LOOKUP_REQUEST_NOT_FOUND
          - TOKEN_NOT_FOUND
          - BULK_UPLOAD_JOB_NOT_FOUND
          - REFERENCE_NOT_FOUND
          - UMA_NOT_FOUND
          - STABLECOIN_PROVIDER_ACCOUNT_NOT_FOUND
        message:
          type: string
          description: Error message
        details:
          type: object
          description: Additional error details
          additionalProperties: true
    CardCreateRequest:
      type: object
      required:
      - cardholderId
      - form
      - fundingSources
      properties:
        cardholderId:
          type: string
          description: The id of the `Customer` to issue the card to. The customer must have KYC status `APPROVED`; otherwise the request is rejected with `CARDHOLDER_KYC_NOT_APPROVED`.
          example: Customer:019542f5-b3e7-1d02-0000-000000000001
        platformCardId:
          type: string
          description: Optional platform-specific card identifier. System-generated when omitted, mirroring `platformCustomerId` semantics.
          example: card-emp-aary-001
        form:
          $ref: '#/components/schemas/CardForm'
        fundingSources:
          type: array
          description: Internal account ids to bind as funding sources, in priority order. The first entry is tried first by Authorization Decisioning. Every card must be bound to at least one source, and every source must belong to the cardholder and be denominated in a card-eligible currency (USDB in v1); otherwise the request is rejected with `FUNDING_SOURCE_INELIGIBLE`.
          minItems: 1
          items:
            type: string
          example:
          - InternalAccount:019542f5-b3e7-1d02-0000-000000000002
    CardState:
      type: string
      enum:
      - PENDING_KYC
      - PROCESSING
      - ACTIVE
      - FROZEN
      - CLOSED
      description: 'Lifecycle state of a card.


        | State | Description |

        |-------|-------------|

        | `PENDING_KYC` | The cardholder has not yet completed KYC. Cards in this state cannot transact. |

        | `PROCESSING` | The card has been requested and is being provisioned with the issuer. |

        | `ACTIVE` | The card is live and can authorize transactions. |

        | `FROZEN` | The card is temporarily disabled by the platform. New authorizations are declined with `CARD_PAUSED`. Existing settlements and refunds continue to reconcile. |

        | `CLOSED` | The card is permanently closed. Terminal, irreversible state. |

        '
    CardUpdateRequest:
      type: object
      description: Update request for `PATCH /cards/{id}`. At least one of `state` or `fundingSources` must be supplied. `state` transitions are limited to `ACTIVE ⇄ FROZEN` and `ACTIVE | FROZEN → CLOSED`; any other transition returns `409 INVALID_STATE_TRANSITION`. `CLOSED` is terminal and irreversible and cannot be combined with `fundingSources`. `fundingSources`, when suppl

# --- truncated at 32 KB (42 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/lightspark/refs/heads/main/openapi/lightspark-cards-api-openapi.yml