Browse the docs

List card products

GET /v1/api-gateway/card/card-products

The response is one page, not the whole catalog: page with current_page / per_page (default 1 / 10) and read pagination.last_page to know how many there are. Any other paging parameter is ignored rather than rejected.

Request

Authentication: your API key in the x-api-key header.

Query parameters

FieldTypeDescription
current_pageintegerPage number, starting at 1. Default 1. Matches pagination.current_page in the response.
per_pageintegerCard products per page. Minimum 1. Default 10. No maximum: the catalog is paged in memory, so pagination.per_page always reports the value you sent.

Example request

cURL

curl --request GET \
     --url 'https://api.themooncard.com/v1/api-gateway/card/card-products' \
     --header 'x-api-key: YOUR_API_KEY'

Responses

200 Success
FieldTypeDescription
card_products requiredarray of object
card_products[].id requiredstringCard product id. Use it as card_product_id when issuing a card.
card_products[].name requiredstringProduct display name.
card_products[].currency requiredstring, nullableISO-4217 currency the product is denominated in, or null.
card_products[].in_stock requiredbooleanAlways true: out-of-stock products are not listed.
card_products[].open_or_closed_loop requiredstring, nullableWhether the product is an open-loop card, which works anywhere the card network is accepted, or a closed-loop card, which can only be spent with one merchant. Null when the product does not record it.
card_products[].for_use_in_countries requiredobjectCountries the product can be used in; in practice an array of ISO-3166 alpha-2 codes.
card_products[].minimum_value requirednumber, nullableSmallest amount that can be loaded, or null when unrestricted.
card_products[].maximum_value requirednumber, nullableLargest amount that can be loaded, or null when unrestricted.
card_products[].denominations requiredobjectFixed denominations offered by the product, or null when any amount is allowed.
card_products[].supports_merchant_lock requiredbooleanWhether a card issued from this product can be locked to one merchant. Pass merchant_lock on POST /cards only with a product where this is true; any other product is rejected with MERCHANT_LOCK_UNSUPPORTED. A lock is only as good as the merchant identity that arrives with an authorization, and not every product's authorizations carry one.
card_products[].categories requiredarray of stringLowercase category names of the product brand, e.g. ["gaming", "retail"]. Empty when uncategorized.
card_products[].merchant requiredobject, nullableBrand the product belongs to, or null.
card_products[].merchant.id requiredstringBrand id.
card_products[].merchant.name requiredstringBrand display name.
card_products[].merchant.description requiredstring, nullable
card_products[].merchant.primary_brand_color requiredstringHex colour, e.g. "#000000".
card_products[].merchant.primary_text_color requiredstringHex colour to use for text on top of primary_brand_color.
card_products[].merchant.logo_s3_url requiredstring, nullableBrand logo URL, or null.
card_products[].merchant.card_image_url requiredstring, nullableCard artwork URL, or null.
card_products[].default_discount requirednumberDiscount applied to your organization for this product, as a percentage; 0 when none.
pagination requiredobject
pagination.total requiredintegerTotal number of items across all pages.
pagination.last_page requiredintegerNumber of the last page (0 when there are no items).
pagination.prev_page requiredinteger, nullablePrevious page number, or null on the first page.
pagination.next_page requiredinteger, nullableNext page number, or null on the last page.
pagination.per_page requiredintegerPage size that was applied.
pagination.current_page requiredinteger1-based current page.
pagination.from requiredinteger1-based index of the first item on this page (0 when empty).
pagination.to requiredinteger1-based index of the last item on this page (0 when empty).

JSON

{
  "card_products": [
    {
      "id": "a8358b18-be77-41b7-af4d-f4e9760cba86",
      "name": "Moon Prepaid Visa (USD)",
      "currency": "USD",
      "in_stock": true,
      "open_or_closed_loop": "OPEN",
      "for_use_in_countries": [
        "US"
      ],
      "minimum_value": 5,
      "maximum_value": 1000,
      "denominations": null,
      "supports_merchant_lock": false,
      "categories": [
        "prepaid"
      ],
      "merchant": {
        "id": "e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a8b",
        "name": "Acme Superstore",
        "description": "Everything, delivered.",
        "primary_brand_color": "#0B1F3B",
        "primary_text_color": "#FFFFFF",
        "logo_s3_url": "https://assets.paywithmoon.com/brands/acme/logo.png",
        "card_image_url": "https://assets.paywithmoon.com/brands/acme/card.png"
      },
      "default_discount": 0
    }
  ],
  "pagination": {
    "total": 1,
    "last_page": 1,
    "prev_page": null,
    "next_page": null,
    "per_page": 10,
    "current_page": 1,
    "from": 1,
    "to": 1
  }
}
400 Error

Validation failed (errors[] lists each offending field) or a domain rule rejected the request ({ message, code }).

The body is the standard error object: see Errors.

401 Error

Missing or invalid credentials, e.g. { "message": "Invalid API Key", "code": "UNAUTHORIZED" }.

The body is the standard error object: see Errors.

500 Error

Unexpected server error. Body is { message: "Internal server error", code: "INTERNAL_SERVER_ERROR" }.

The body is the standard error object: see Errors.

Last updated April 30, 2026