> ## Documentation Index
> Fetch the complete documentation index at: https://spreecommerce.org/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Store Credits & Gift Cards

> How Spree models store credits and gift cards — stored value balances, redeemable codes, and checkout usage for refunds, loyalty, and gifting.

## Overview

Spree provides two stored value mechanisms that customers can use at checkout:

* **Store Credits** - Value assigned directly to a customer's account by admins (refunds, loyalty rewards, compensation)
* **Gift Cards** - Value with a redeemable code that can be shared and redeemed by anyone

| Feature | Store Credit | Gift Card |
| - | - | - |
| Purpose | Refunds, loyalty rewards, compensation | Gifting, promotions, marketing |
| Requires account | Yes (tied to customer account) | No (guests can use at checkout) |
| Transferable | No | Yes (code can be shared) |
| Has code | No | Yes |
| Created by | Admin | Admin |
| Assignment | Directly to customer | Applied to order via code |
| Expiration | Never expire | Optional, per card |

## Store Credits

Store Credits are monetary values assigned directly to a customer's account. They are commonly used for:

* Refunds (instead of returning money to original payment method)
* Loyalty rewards
* Customer compensation
* Promotional credits

### Store Credit Model

```mermaid theme={"theme":"night-owl"}
erDiagram
    StoreCredit ||--o{ StoreCreditEvent : "has many"
    StoreCredit ||--o{ Payment : "source for"
    StoreCredit }o--|| User : "belongs to"
    StoreCredit }o--|| Store : "belongs to"
    StoreCredit }o--o| StoreCreditCategory : "belongs to"
    StoreCredit }o--o| StoreCreditType : "belongs to"

    StoreCredit {
        decimal amount
        decimal amount_used
        decimal amount_authorized
        string currency
        string memo
    }

    StoreCreditCategory {
        string name
    }

    StoreCreditType {
        string name
        integer priority
    }

    StoreCreditEvent {
        string action
        decimal amount
        string authorization_code
    }
```

### Store Credit Attributes

| Attribute | Description | Example |
| - | - | - |
| `amount` | Total credit amount | `100.00` |
| `amount_used` | Amount already spent | `25.00` |
| `amount_authorized` | Amount currently authorized for pending orders | `0.00` |
| `currency` | Currency code | `USD` |
| `memo` | Optional note about the credit | `Refund for order #R123` |

### Why a Credit Exists

Store credits carry no category and no type. Two fields cover it instead:

| Field | What it tells you |
| - | - |
| `originator` | The return, exchange, claim or gift card that issued the credit, or nothing when an admin issued it by hand |
| `memo` | The free-text reason, written by the refund workflows or by the admin |

Store credits do not expire; only gift cards carry an expiry, on their own
record. Which credit is spent first is decided by `Spree::StoreCredit.oldest_first`.

<Note>
  `Spree::StoreCreditCategory` and `Spree::StoreCreditType` still exist as
  deprecated shells for compatibility. Nothing writes them.
</Note>

### Store Credit Events

Every action on a store credit is recorded as an event for audit purposes:

| Action | Description |
| - | - |
| `allocation` | Initial credit was assigned |
| `authorize` | Credit was authorized for an order |
| `capture` | Authorized credit was captured |
| `void` | Authorization was voided |
| `credit` | Credit was returned (e.g., order canceled) |

### Assigning Store Credits

Store credits are managed in the Admin Panel:

1. Navigate to **Customers** in the Admin Panel
2. Select a customer
3. Go to the **Store Credits** tab
4. Click **Add Store Credit**
5. Enter the amount, currency, and optional memo
6. Click **Create**

Store credits can also be created via the [Admin API](/docs/api-reference/admin-api/introduction), as a nested resource under the customer:

<CodeGroup>
  ```typescript Admin SDK theme={"theme":"night-owl"}
  import { createAdminClient } from '@spree/admin-sdk'

  const client = createAdminClient({
    baseUrl: 'https://store.example.com',
    secretKey: 'sk_xxx',
  })

  const credit = await client.customers.storeCredits.create('cus_xxx', {
    amount: '25.00',
    currency: 'USD',
    memo: 'Goodwill credit for delayed shipment',
  })
  ```

  ```bash CLI theme={"theme":"night-owl"}
  spree api post /customers/cus_xxx/store_credits -d '{
    "amount": "25.00",
    "currency": "USD",
    "memo": "Goodwill credit"
  }'
  ```
</CodeGroup>

### Listing Store Credits Across Customers

Credits are written per customer, but read across them. The Admin API exposes a
read-only list so an integration can answer what the store owes without walking
every customer:

<CodeGroup>
  ```typescript Admin SDK theme={"theme":"night-owl"}
  const { data: credits, meta } = await client.storeCredits.list({
    outstanding: true,
    expand: ['customer', 'created_by'],
  })

  // One row per currency, summed over the same filter as the page.
  meta.totals.forEach((total) => {
    console.log(total.currency, total.display_amount_remaining)
  })
  ```

  ```bash CLI theme={"theme":"night-owl"}
  spree api get /store_credits -q 'outstanding=true'
  ```
</CodeGroup>

Filters mirror the questions a merchant asks: `customer_id`,
`customer_email_cont`, `currency`, `created_by_id`, `memo_cont`, a
`created_at` range, and two scopes — `outstanding` (money still owed versus
money spent) and `from_gift_card` (whether a gift card redemption created it).

Each credit's ledger is its own endpoint:

<CodeGroup>
  ```typescript Admin SDK theme={"theme":"night-owl"}
  const { data: events } = await client.storeCredits.events.list('credit_xxx')
  ```

  ```bash CLI theme={"theme":"night-owl"}
  spree api get /store_credits/credit_xxx/events
  ```
</CodeGroup>

Creating, updating and deleting a credit remain nested under the customer that
holds it — a credit without an owner has nobody to pay.

### Store Credit Events

The store credit system publishes lifecycle events:

| Event | Description |
| - | - |
| `store_credit.created` | Store credit was created |
| `store_credit.updated` | Store credit was updated |

## Gift Cards

Gift Cards are stored value codes created by admins that can be shared and redeemed by customers. When redeemed, they create a Store Credit on the customer's account.

### Gift Card Model

```mermaid theme={"theme":"night-owl"}
erDiagram
    GiftCard }o--|| Store : "belongs to"
    GiftCard }o--o| User : "belongs to"
    GiftCard }o--o| GiftCardBatch : "belongs to"
    GiftCard ||--o{ StoreCredit : "originator for"

    GiftCard {
        string code
        string status
        decimal amount
        decimal amount_used
        decimal amount_authorized
        string currency
        date expires_at
        datetime redeemed_at
    }

    GiftCardBatch {
        string prefix
        integer codes_count
        decimal amount
        string currency
        date expires_at
    }
```

### Gift Card Attributes

| Attribute | Description | Example |
| - | - | - |
| `code` | Unique redemption code | `abc1234def` |
| `amount` | Total gift card value | `50.00` |
| `amount_used` | Amount already redeemed | `0.00` |
| `status` | Current status | `active` |
| `currency` | Currency code | `USD` |
| `expires_at` | Optional expiration date | `2025-12-31` |

### Gift Card Statuses

| Status | Description | How it gets there |
| - | - | - |
| `active` | Available for redemption | The status a card is created with |
| `partially_redeemed` | Some value has been redeemed | `Spree::GiftCards::Redeem`, when a balance remains |
| `redeemed` | Fully redeemed | `Spree::GiftCards::Redeem`, when nothing is left |
| `canceled` | Voided, and no longer spendable | `Spree::GiftCards::Cancel` |

Redemption does not need the caller to choose: `Spree::GiftCards::Redeem`
looks at what is left on the card and marks it partially or fully redeemed
accordingly. A card can be partially redeemed more than once, and each spend
publishes its own event.

Cancelling is refused once a card has been spent against, so cancellation can
never take back value a customer has already used.

<Note>
  Gift cards can also be `expired` if `expires_at` date has passed and the card hasn't been fully redeemed.
</Note>

### Gift Card Lifecycle

```mermaid theme={"theme":"night-owl"}
flowchart TB
    A[Admin creates Gift Card] --> B[Code generated]
    B --> C[Admin shares code with recipient]
    C --> D[Recipient enters code at checkout]
    D --> E[Store Credit created for customer]
    E --> F[Gift Card marked as redeemed]
    F --> G[Customer uses Store Credit]
```

### Creating Gift Cards

#### Single Gift Card

1. Navigate to **Gift Cards** in the Admin Panel
2. Click **Create Gift Card**
3. Enter the amount and optional expiration date
4. Click **Create**
5. Share the generated code with the recipient

Gift cards can also be created via the [Admin API](/docs/api-reference/admin-api/introduction). The code is generated automatically if you don't supply one:

<CodeGroup>
  ```typescript Admin SDK theme={"theme":"night-owl"}
  import { createAdminClient } from '@spree/admin-sdk'

  const client = createAdminClient({
    baseUrl: 'https://store.example.com',
    secretKey: 'sk_xxx',
  })

  const giftCard = await client.giftCards.create({
    amount: '50.00',
    currency: 'USD',
    expires_at: '2026-12-31',
  })

  console.log(giftCard.code) // share this with the recipient
  ```

  ```bash CLI theme={"theme":"night-owl"}
  spree api post /gift_cards -d '{
    "amount": "50.00",
    "currency": "USD",
    "expires_at": "2026-12-31"
  }'
  ```
</CodeGroup>

#### Batch Gift Card Generation

For promotions or bulk distribution, you can create multiple gift cards at once using Gift Card Batches:

1. Navigate to **Gift Cards** in the Admin Panel
2. Click **Create Batch**
3. Enter:
   * **Prefix** - Code prefix for easy identification (e.g., `HOLIDAY`)
   * **Count** - Number of cards to generate
   * **Amount** - Value per card
   * **Expiration** - Optional expiration date
4. Click **Create**

Batches can also be created via the Admin API:

<CodeGroup>
  ```typescript Admin SDK theme={"theme":"night-owl"}
  const batch = await client.giftCardBatches.create({
    prefix: 'HOLIDAY',
    codes_count: 1000,
    amount: '25.00',
    currency: 'USD',
    expires_at: '2026-12-31',
  })
  ```

  ```bash CLI theme={"theme":"night-owl"}
  spree api post /gift_card_batches -d '{
    "prefix": "HOLIDAY",
    "codes_count": 1000,
    "amount": "25.00",
    "currency": "USD",
    "expires_at": "2026-12-31"
  }'
  ```
</CodeGroup>

<Info>
  Large batches are processed in the background to avoid timeout issues.
</Info>

### Redeeming Gift Cards

Gift cards can be redeemed by both **registered customers** and **guest visitors** at checkout. This is a key difference from Store Credits, which require a customer account.

<Info>
  Unlike Store Credits which are tied to a customer account, Gift Cards can be applied directly to an order during checkout - no account required. This makes them ideal for gifting to anyone.
</Info>

When a gift card is applied to an order:

* The gift card value is used to pay for the order
* The gift card is marked as redeemed (or partially redeemed)
* No Store Credit is created for guest checkouts

Gift cards are applied via a dedicated `POST /api/v3/store/carts/:cart_id/gift_cards` endpoint (separate from the `discount_codes` endpoint used for promotion codes); the discount-codes endpoint does not handle gift cards. See the [cart & checkout SDK guide](/docs/developer/sdk/store/cart-checkout) for the full cart flow these calls belong to.

<CodeGroup>
  ```typescript Store SDK theme={"theme":"night-owl"}
  // Apply gift card code to cart (works for guests and registered customers)
  // Gift cards use a dedicated endpoint — they reduce amount_due, not total
  const cart = await client.carts.giftCards.apply('cart_abc123', 'abc1234def', {
    spreeToken: '<token>',
  })

  // Remove gift card (ID from cart.gift_card.id)
  await client.carts.giftCards.remove('cart_abc123', cart.gift_card.id, {
    spreeToken: '<token>',
  })
  ```

  ```bash cURL theme={"theme":"night-owl"}
  # Apply gift card to cart (works for guests and registered customers)
  curl -X POST 'https://api.mystore.com/api/v3/store/carts/cart_abc123/gift_cards' \
    -H 'X-Spree-Api-Key: pk_xxx' \
    -H 'X-Spree-Token: <token>' \
    -H 'Content-Type: application/json' \
    -d '{ "code": "abc1234def" }'
  ```
</CodeGroup>

### Gift Card Events

The gift card system publishes lifecycle events:

| Event | Description |
| - | - |
| `gift_card.created` | Gift card was created |
| `gift_card.redeemed` | Gift card was fully redeemed |
| `gift_card.partially_redeemed` | Gift card was partially redeemed |

## Using at Checkout

Store Credits and Gift Cards work differently at checkout:

* **Store Credits** - Require a customer account; applied from the customer's balance
* **Gift Cards** - Can be used by anyone (guests included); applied directly to the order via code

Both are applied before the customer chooses how to pay, and neither appears among the cart's payment methods. An order uses one or the other, never both. A gift card covers as much of the total as its balance allows and keeps up as the total changes. See the [cart & checkout SDK guide](/docs/developer/sdk/store/cart-checkout) for the calls.

### Checkout Flow

```mermaid theme={"theme":"night-owl"}
flowchart TB
    A[Customer proceeds to payment] --> B{Guest or Registered?}
    B -->|Registered| C{Has Store Credit?}
    B -->|Guest| D{Has Gift Card code?}
    C -->|Yes| E[Display available balance]
    C -->|No| D
    D -->|Yes| F[Apply Gift Card to order]
    D -->|No| G[Show payment methods]
    E --> H{Apply Store Credit?}
    H -->|Yes| I[Authorize store credit]
    H -->|No| D
    F --> J{Covers order total?}
    I --> J
    J -->|Yes| K[Complete order]
    J -->|No| G
    G --> L[Customer pays remaining balance]
    L --> K
```

### Store Credit Priority

When a registered customer holds several store credits, the oldest is spent
first (`Spree::StoreCredit.oldest_first`). Store credits do not expire — only
gift cards carry an expiry, on their own record.

## Related Documentation

* [Payments](/docs/developer/core-concepts/payments) — Payment processing and methods
* [Orders](/docs/developer/core-concepts/orders) — Order management
* [Customers](/docs/developer/core-concepts/customers) — Customer management
* [Events](/docs/developer/core-concepts/events) — Event system and subscribers
* [Admin SDK Quickstart](/docs/developer/sdk/admin/quickstart) — Set up and authenticate the Admin SDK
* [Monetary Amounts](/docs/api-reference/store-api/monetary-amounts) — How the API represents `amount`, `amount_used`, and other money fields


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.