Developers
REST API
Cardigan exposes an HTTP API covering the same operations its own storefront, checkout and POS extensions use, so you can integrate gift card functionality into a headless storefront, a middleware layer, or your own internal tooling.
Version 1 is being deprecated
The v2 API described on this page replaces version 1, which is no longer publicly supported and is being retired. The previous documentation is archived at Cardigan API Spec v1.1.
OpenAPI specification
The API is defined by an OpenAPI 3.1 document, published at:
https://app.runcardigan.com/api/v2/openapi.yaml
Base URL
Every endpoint is scoped to a single store:
https://app.runcardigan.com/api/v2/{store-subdomain}/
The subdomain is your store's .myshopify.com prefix - for mystore.myshopify.com, use mystore.
Requests and responses are JSON.
Authentication
Every endpoint in the v2 API requires some form of authentication. The appropriate authentication method depends on the specific endpoint, and each endpoint below names the one to send.
Authentication method: API token
Your store's Cardigan API token, sent as a bearer token:
Authorization: Bearer {your-api-token}
Find your store's token in the Cardigan Configuration page, under API access.
Treat your API token as a secret
The token carries your authority over your provider account, so treat it as a production secret. Never expose it in browser-side code.
Authentication method: Session token
A session token minted by Shopify for a checkout or customer account UI extension, sent as a bearer token.
Endpoints that act on a single customer's data require one, because Cardigan reads the customer's identity from the token rather than from a parameter you send. That means they can only be called from a Shopify surface able to mint a session token, and not from a server or a headless storefront.
Request context
Several optional parameters affect which of your configured profiles is used to handle a request, and the locale it responds in. All are accepted on every endpoint.
| Parameter | Purpose |
|---|---|
currency | The currency of the transaction, as an ISO-4217 code. Defaults to your store's currency. Used to select a matching profile. |
location_id | The Shopify location involved, as a numeric ID or a global ID. Used to select a matching profile. |
locale | The locale to return messages and formatted values in. Defaults to your store's primary locale. |
See Profile routing for how these combine to determine which provider account a request is sent to. A request that matches no profile returns a no_matching_profile error.
Errors
Every failure returns a single error object:
{
"error": {
"type": "invalid_request_error",
"code": "card_not_found",
"message": "Could not find a card with the provided details.",
"detail": "mystore.myshopify.com"
}
}
code is stable and is what you should branch on.
type groups codes by what you can do about the failure - present a different credential, send different parameters, back off, or retry - so you can handle a whole class of failures without enumerating every code. It is one of api_error, authentication_error, invalid_request_error or rate_limit_error.
message is localised to the request's locale and safe to show to a customer.
detail carries the context the failure came with, such as a provider's own message or the value that was rejected. It's omitted when there is none, and it's written for your logs rather than for a customer.
| Status | Meaning | Codes |
|---|---|---|
400 | The request was missing a parameter or sent one that couldn't be read | invalid_request, currency_required |
401 | The credential was missing, malformed, or issued for another store | unauthorized |
404 | The store or the card couldn't be found, or the provider refused the lookup | shop_not_found, card_not_found, card_not_active, card_expired, unknown |
422 | The request was understood but couldn't be processed with this store's setup | no_matching_profile, missing_store_credit_scopes |
429 | You've exceeded 30 requests a minute from one IP address | too_many_requests |
Check a gift card balance
POST /cards/balance.json
Authenticates with your API token.
| Field | Required | Notes |
|---|---|---|
number | Yes | The gift card number |
pin | Depends | Required unless your store's PIN behaviour says otherwise |
include_transactions | No | Set to true to include the card's transaction history, for providers that support it |
{
"card": {
"currency": "CAD",
"balance": "100.0",
"balance_formatted": "$100",
"expires_at": "2032-06-15T20:00:00-04:00",
"expires_at_formatted": "2032-06-15",
"last_characters": "3203"
}
}
Amounts are decimal strings in the card's own currency, which isn't necessarily your store's currency. expires_at and expires_at_formatted are null for a card that doesn't expire, and for providers that don't report expiry.
Use last_characters rather than the full number when showing the card back to a customer.
The balance is the provider's own reading. A hold Cardigan is carrying against the card for an in-progress checkout may reduce it, depending on the provider.
With include_transactions set, a transactions array is returned alongside the card, newest first, each entry carrying id, type, amount, amount_formatted, reference, timestamp and timestamp_formatted. type is one of credit, debit, sale or unknown. Providers that can't report history return an empty array rather than an error.
Synchronise a wallet
POST /wallet/sync.json
Authenticates with a Shopify session token.
Brings a customer's Shopify store credit balance into line with the balance their provider holds, and returns the result. See Wallets for more context.
| Field | Required | Notes |
|---|---|---|
currency | Yes | The currency of the wallet to synchronise, as an ISO-4217 code |
context | No | Pass intercept to bypass the 60-second debounce and force a live reading |
{
"wallet": {
"currency": "USD",
"balance": "25.00",
"balance_formatted": "$25 USD",
"changed": true,
"stale": false,
"synced_at": "2026-08-06T09:00:00Z"
}
}
A synchronisation the server declines to run answers 200 with stale set, rather than failing. The balance returned is then the last one Cardigan held.
Cardigan's own Wallet Synchronisation checkout extension is the intended caller. It's unlikely you'll need to call it yourself - if you have a use case that does, get in touch.
Provider capability
The API surface is the same for every provider, but what each provider actually supports differs - not all report transaction history, and not all hold funds.
Check the relevant page in the Providers section before building against an endpoint, and expect an error rather than silent success where an operation isn't supported.