> Documentation index: [Saleor](/llms.txt) · [This section](/developer/llms.txt)
> Source: https://docs.saleor.io/developer/gift-cards

# Gift Cards

Gift cards in Saleor are digital codes that customers can redeem during checkout to reduce the total order amount. In Saleor, they can be created by staff or purchased directly at checkout.

Gift cards are not assigned to any channel and can be used in any channel whose currency matches the gift card's currency.

note

**Gift Cards vs Vouchers**

Gift cards are currency-based and usable across channels with the same currency. Depending on how gift cards are used they may reduce the total price of a checkout. Vouchers discount the subtotal, unit price, or shipping and are scoped to channels.

<a id="creating-and-managing-gift-cards"></a>

## Creating and Managing Gift Cards

Staff users with the `MANAGE_GIFT_CARD` permission can create gift cards directly in Saleor and send them to customers. Gift cards can be created individually or in bulk, and can have an expiry date set or be non-expiring.

<a id="creating-gift-cards"></a>

### Creating Gift Cards

<a id="single-gift-card-creation"></a>

#### Single Gift Card Creation

The following example shows how to create a single gift card. Once you provide the `userEmail` and configure the email plugin for the given channel, the gift card is sent to the customer, and the `SENT_TO_CUSTOMER` event is created. In this example, providing the `expiryDate` value will set the expiry date. If you want to create a non-expiring card, do not provide the `expiryDate` value.

**Mutation**

```graphql
mutation giftCardCreate($input: GiftCardCreateInput!) {
  giftCardCreate(input: $input) {
    giftCard {
      id
      code
      last4CodeChars
      isActive
      expiryDate
      initialBalance {
        currency
        amount
      }
      currentBalance {
        currency
        amount
      }
      events {
        type
      }
    }
  }
}
```

**Variables**

```json
{
  "input": {
    "balance": {
      "amount": 100,
      "currency": "USD"
    },
    "userEmail": "test@example.com",
    "channel": "channel-USD",
    "expiryDate": "2050-10-10",
    "isActive": true
  }
}
```

**Result**

```json
{
  "data": {
    "giftCardCreate": {
      "giftCard": {
        "id": "R2lmdENhcmQ6MjQ1",
        "code": "0A65-0A28-1347",
        "last4CodeChars": "1347",
        "isActive": true,
        "expiryDate": "2050-10-10",
        "initialBalance": {
          "currency": "USD",
          "amount": 100
        },
        "currentBalance": {
          "currency": "USD",
          "amount": 100
        },
        "events": [
          {
            "type": "ISSUED"
          }
        ]
      }
    }
  }
}
```

<a id="bulk-gift-card-creation"></a>

#### Bulk Gift Card Creation

Creating gift cards in bulk is similar, but you need to specify the number of gift cards to create and the tag value which will be assigned to all created gift cards.

**Mutation**

```graphql
mutation giftCardBulkCreate($input: GiftCardBulkCreateInput!) {
  giftCardBulkCreate(input: $input) {
    giftCards {
      id
      code
      isActive
    }
  }
}
```

**Variables**

```json
{
  "input": {
    "count": 5,
    "tags": ["example-tag"],
    "isActive": true,
    "balance": {
      "amount": 200,
      "currency": "USD"
    }
  }
}
```

**Result**

```json
{
  "data": {
    "giftCardBulkCreate": {
      "giftCards": [
        {
          "id": "R2lmdENhcmQ6MjQ2",
          "code": "F5A2-81C9-E289",
          "isActive": true
        },
        {
          "id": "R2lmdENhcmQ6MjQ3",
          "code": "FA61-39FC-03DE",
          "isActive": true
        },
        {
          "id": "R2lmdENhcmQ6MjQ4",
          "code": "0A7B-2E6F-06A8",
          "isActive": true
        },
        {
          "id": "R2lmdENhcmQ6MjQ5",
          "code": "F7C9-7479-8AE6",
          "isActive": true
        },
        {
          "id": "R2lmdENhcmQ6MjUw",
          "code": "60C5-10B9-DF19",
          "isActive": true
        }
      ]
    }
  }
}
```

After creation, you can export the gift card codes to CSV. Read more about [exporting gift cards](/developer/export/export-gift-cards.md).

<a id="managing-gift-cards"></a>

### Managing Gift Cards

<a id="resending-gift-cards"></a>

#### Resending Gift Cards

You can resend the gift card to the customer at any time after creation. If the `userEmail` is not provided, the card is sent to the customer who already used the card. If the card hasn't been used yet, it is sent to the customer who created it.

**Mutation**

```graphql
mutation giftCardResend($input: GiftCardResendInput!) {
  giftCardResend(input: $input) {
    giftCard {
      id
      code
      events {
        type
        user {
          email
        }
        app {
          name
        }
      }
    }
  }
}

```

**Variables**

```json
{
  "input": {
    "id": "R2lmdENhcmQ6MjUw",
    "channel": "default-channel",
    "email": "saleor@example.com"
  }
}
```

**Result**

```json
{
  "data": {
    "giftCardResend": {
      "giftCard": {
        "id": "R2lmdENhcmQ6MjUw",
        "code": "60C5-10B9-DF19",
        "events": [
          {
            "type": "ISSUED",
            "user": {
              "email": "staff_user@saleor.io"
            },
            "app": null
          }
        ]
      }
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 1,
      "maximumAvailable": 50000
    }
  }
}
```

<a id="updating-gift-cards"></a>

#### Updating Gift Cards

After creation, the tag, expiry date, and balance amount can be updated.

note

Updating the balanceAmount will update both current and initial ballance, no matter if the card has already been used.

**Mutation**

```graphql
mutation giftCardUpdate($id: ID!, $input: GiftCardUpdateInput!) {
  giftCardUpdate(id: $id, input: $input) {
    giftCard {
      id
      expiryDate
      initialBalance {
        currency
        amount
      }
      currentBalance {
        currency
        amount
      }
      events {
        type
        expiryDate
        oldExpiryDate
        oldTags
        tags
        balance {
          initialBalance {
            amount
            currency
          }
          oldInitialBalance {
            amount
            currency
          }
          currentBalance {
            amount
            currency
          }
          oldCurrentBalance {
            amount
            currency
          }
        }
      }
    }
  }
}
```

**Variables**

```json
{
  "id": "R2lmdENhcmQ6MjUw",
  "input": {
    "balanceAmount": 70,
    "expiryDate": "2040-10-10",
    "addTags": [
      "new-tag"
    ]
  }
}
```

**Result**

```json
{
  "data": {
    "giftCardUpdate": {
      "giftCard": {
        "id": "R2lmdENhcmQ6MjUw",
        "expiryDate": "2040-10-10",
        "initialBalance": {
          "currency": "USD",
          "amount": 70
        },
        "currentBalance": {
          "currency": "USD",
          "amount": 70
        },
        "events": [
          {
            "type": "ISSUED",
            "expiryDate": null,
            "oldExpiryDate": null,
            "oldTags": null,
            "tags": null,
            "balance": {
              "initialBalance": {
                "amount": 200,
                "currency": "USD"
              },
              "oldInitialBalance": null,
              "currentBalance": {
                "amount": 200,
                "currency": "USD"
              },
              "oldCurrentBalance": null
            }
          },
          {
            "type": "RESENT",
            "expiryDate": null,
            "oldExpiryDate": null,
            "oldTags": null,
            "tags": null,
            "balance": null
          },
          {
            "type": "BALANCE_RESET",
            "expiryDate": null,
            "oldExpiryDate": null,
            "oldTags": null,
            "tags": null,
            "balance": {
              "initialBalance": {
                "amount": 70,
                "currency": "USD"
              },
              "oldInitialBalance": {
                "amount": 200,
                "currency": "USD"
              },
              "currentBalance": {
                "amount": 70,
                "currency": "USD"
              },
              "oldCurrentBalance": {
                "amount": 200,
                "currency": "USD"
              }
            }
          },
          {
            "type": "EXPIRY_DATE_UPDATED",
            "expiryDate": "2040-10-10",
            "oldExpiryDate": null,
            "oldTags": null,
            "tags": null,
            "balance": null
          },
          {
            "type": "TAGS_UPDATED",
            "expiryDate": null,
            "oldExpiryDate": null,
            "oldTags": [
              "example-tag"
            ],
            "tags": [
              "example-tag",
              "new-tag"
            ],
            "balance": null
          }
        ]
      }
    }
  }
}
```

<a id="adjusting-the-balance"></a>

#### Adjusting the Balance

Added in Saleor 3.23.

Use the [`giftCardBalanceAdjust`](/api-reference/gift-cards/mutations/gift-card-balance-adjust.md) mutation to change a card's current balance by an `amount` instead of overwriting it. A positive amount tops the card up, and a negative amount deducts from it.

Unlike `giftCardUpdate` (which sets `balanceAmount` to an absolute value and records a `BALANCE_RESET` event), the adjustment is applied atomically at the database level. This makes it safe to run while a card is being charged in a concurrent checkout, so no update is silently lost. Each adjustment records a `BALANCE_ADJUSTED` event.

The mutation applies two clamping rules:

-   A deduction that would take the balance below zero clamps the current balance to zero.
-   A top-up above the current initial balance raises the initial balance to the new current balance.

The `amount` cannot be zero and must match the currency precision of the card. The staff member or app needs the `MANAGE_GIFT_CARD` permission.

**Mutation**

```graphql
mutation giftCardBalanceAdjust($id: ID!, $amount: Decimal!) {
  giftCardBalanceAdjust(id: $id, amount: $amount) {
    giftCard {
      id
      initialBalance {
        currency
        amount
      }
      currentBalance {
        currency
        amount
      }
      events {
        type
        balance {
          currentBalance {
            amount
            currency
          }
          oldCurrentBalance {
            amount
            currency
          }
        }
      }
    }
    errors {
      field
      code
      message
    }
  }
}
```

**Variables**

```json
{
  "id": "R2lmdENhcmQ6MjUw",
  "amount": -20
}
```

**Result**

```json
{
  "data": {
    "giftCardBalanceAdjust": {
      "giftCard": {
        "id": "R2lmdENhcmQ6MjUw",
        "initialBalance": {
          "currency": "USD",
          "amount": 70
        },
        "currentBalance": {
          "currency": "USD",
          "amount": 50
        },
        "events": [
          {
            "type": "BALANCE_ADJUSTED",
            "balance": {
              "currentBalance": {
                "amount": 50,
                "currency": "USD"
              },
              "oldCurrentBalance": {
                "amount": 70,
                "currency": "USD"
              }
            }
          }
        ],
        "errors": []
      }
    }
  }
}
```

<a id="activating-and-deactivating-gift-cards"></a>

#### Activating and Deactivating Gift Cards

Cards can be activated and deactivated at any time, either individually or in bulk.

**Mutation**

```graphql
mutation giftCardDeactivate($id: ID!) {
  giftCardDeactivate(id: $id) {
    giftCard {
      id
      isActive
      events {
        type
      }
    }
  }
}
```

**Variables**

```json
{
  "id": "R2lmdENhcmQ6MjUw"
}
```

**Result**

```json
{
  "data": {
    "giftCardDeactivate": {
      "giftCard": {
        "id": "R2lmdENhcmQ6MjUw",
        "isActive": false,
        "events": [
          {
            "type": "ISSUED"
          },
          {
            "type": "RESENT"
          },
          {
            "type": "BALANCE_RESET"
          },
          {
            "type": "EXPIRY_DATE_UPDATED"
          },
          {
            "type": "TAGS_UPDATED"
          },
          {
            "type": "DEACTIVATED"
          }
        ]
      }
    }
  }
}
```

For bulk operations, use [`giftCardBulkActivate`](/api-reference/gift-cards/mutations/gift-card-bulk-activate.md) and [`giftCardBulkDeactivate`](/api-reference/gift-cards/mutations/gift-card-bulk-deactivate.md) mutations.

<a id="restricting-gift-cards-to-a-customer"></a>

## Restricting Gift Cards to a Customer

Added in Saleor 3.23.

By default, a gift card is a **bearer instrument**: whoever holds the code can redeem it, including in guest checkout. Customer assignment is an **opt-in restriction** layered on top of this default. Once a card is restricted to a customer, only that customer's account can use it, and the card can no longer be redeemed in guest checkout.

Assignment is distinct from `usedBy`:

-   `assignedTo` is forward-looking — the customer who is **allowed** to spend the card. It is a restriction that staff set on purpose.
-   `usedBy` is historical — the last customer who **spent** the card. It is an audit record and is deprecated.

note

Assignment is manual only. Saleor never auto-assigns a card to whoever pays with it. A card stays unrestricted until staff explicitly assign it.

<a id="assigning-a-customer"></a>

### Assigning a Customer

You can restrict a card to a customer at creation time by passing `assignedTo` (a customer's user ID) to [`giftCardCreate`](/api-reference/gift-cards/mutations/gift-card-create.md), or afterwards with the [`giftCardAssignUser`](/api-reference/gift-cards/mutations/gift-card-assign-user.md) mutation. Both require the `MANAGE_GIFT_CARD` permission and trigger the `GIFT_CARD_UPDATED` webhook.

Assigning a customer records an `ASSIGNED_TO_USER` event and stores the customer's email on the card.

**Mutation**

```graphql
mutation giftCardAssignUser($id: ID!, $userId: ID!) {
  giftCardAssignUser(id: $id, userId: $userId) {
    giftCard {
      id
      assignedTo {
        id
        email
      }
      assignedToEmail
      events {
        type
        assignedTo {
          oldAssignedToEmail
          currentAssignedToEmail
        }
      }
    }
    errors {
      field
      code
      message
    }
  }
}
```

**Variables**

```json
{
  "id": "R2lmdENhcmQ6MjUw",
  "userId": "VXNlcjoyMg=="
}
```

**Result**

```json
{
  "data": {
    "giftCardAssignUser": {
      "giftCard": {
        "id": "R2lmdENhcmQ6MjUw",
        "assignedTo": {
          "id": "VXNlcjoyMg==",
          "email": "customer@example.com"
        },
        "assignedToEmail": "customer@example.com",
        "events": [
          {
            "type": "ASSIGNED_TO_USER",
            "assignedTo": {
              "oldAssignedToEmail": null,
              "currentAssignedToEmail": "customer@example.com"
            }
          }
        ],
        "errors": []
      }
    }
  }
}
```

A card cannot be assigned when it has already been used in an order, when it is attached to a checkout that has payments, or when it has been used by a [gift card payment transaction](#gift-cards-as-payment-method). In those cases the mutation returns a `CANNOT_ASSIGN` error. If the card is attached to a checkout that has no payments, the card is detached from that checkout as part of the assignment.

note

The link between a gift card and a payment transaction is permanent: cancelling the authorization does **not** release the card for assignment. The link is the record that the card was used.

note

The `assignedTo` field on `GiftCard` requires the `MANAGE_USERS` permission (or the card's owner), while `assignedToEmail` requires `MANAGE_GIFT_CARD` (or being the owner of that gift card). Enforcement at checkout is intentionally generic: a restricted card that does not match the customer is rejected with the same error as any unusable code, so it never reveals whether a card is assigned or to whom. This applies to both the [`transactionInitialize`](#gift-cards-as-payment-method) and the [legacy `checkoutAddPromoCode`](#legacy-using-gift-cards-in-checkout) flows.

<a id="unassigning-a-customer"></a>

### Unassigning a Customer

Use the [`giftCardUnassignUser`](/api-reference/gift-cards/mutations/gift-card-unassign-user.md) mutation to remove the restriction and return the card to bearer behavior. It requires the `MANAGE_GIFT_CARD` permission, triggers the `GIFT_CARD_UPDATED` webhook, and records an `UNASSIGNED_FROM_USER` event.

```graphql
mutation giftCardUnassignUser($id: ID!) {
  giftCardUnassignUser(id: $id) {
    giftCard {
      id
      assignedTo {
        id
      }
      assignedToEmail
    }
    errors {
      field
      code
      message
    }
  }
}
```

tip

Deleting the customer a card is assigned to does **not** lift the restriction. Saleor keeps the assignment trace so the card stays locked rather than silently becoming spendable by anyone again. To make the card usable, reassign it to another customer or unassign it explicitly.

<a id="filtering-by-assigned-customer"></a>

### Filtering by Assigned Customer

The `giftCards` query accepts an `assignedTo` filter that returns the cards restricted to the given customers. This replaces the deprecated `usedBy` filter.

```graphql
query {
  giftCards(first: 10, filter: { assignedTo: ["VXNlcjoyMg=="] }) {
    edges {
      node {
        id
        assignedToEmail
      }
    }
  }
}
```

<a id="setting-up-gift-cards-as-products"></a>

## Setting Up Gift Cards as Products

To allow customers to purchase gift cards, you need to:

1.  Create a product type with `GIFT_CARD` kind
2.  Create a product using this product type
3.  Configure stock settings

note

If you want to have an unlimited number of gift cards in your shop, you should create a stock in a chosen channel with at least one quantity and unset the track inventory flag.

<a id="gift-card-fulfillment-settings"></a>

### Gift Card Fulfillment Settings

The `automaticallyFulfillNonShippableGiftCard` order setting controls when bought gift cards will be created:

-   If set to `True`: Gift card is created during checkout completion
-   If set to `False`: Gift card is created during order fulfillment

<a id="gift-card-expiry-settings"></a>

### Gift Card Expiry Settings

Gift card settings can be configured to:

-   Never expire
-   Expire after a specific period

Example of setting expiry period to 1 year:

**Mutation**

```graphql
mutation giftCardSettingsUpdate($input: GiftCardSettingsUpdateInput!) {
  giftCardSettingsUpdate(input: $input) {
    giftCardSettings {
      expiryType
      expiryPeriod {
        type
        amount
      }
    }
  }
}
```

**Variables**

```json
{
  "input": {
    "expiryType": "EXPIRY_PERIOD",
    "expiryPeriod": {
      "type": "YEAR",
      "amount": 1
    }
  }
}
```

**Result**

```json
{
  "data": {
    "giftCardSettingsUpdate": {
      "giftCardSettings": {
        "expiryType": "EXPIRY_PERIOD",
        "expiryPeriod": {
          "type": "YEAR",
          "amount": 1
        }
      }
    }
  }
```

<a id="gift-cards-as-payment-method"></a>

## Gift Cards as payment method

[Transaction API](/developer/payments/overview.md) allows you to use built-in payment gateway dedicated for consuming gift cards created in Saleor.

<a id="using-gift-cards-in-checkout"></a>

### Using Gift Cards in Checkout

To use a gift card in a checkout, run the [`transactionInitialize`](/api-reference/payments/mutations/transaction-initialize.md) mutation. Following payment gateway details must be included in mutation variables:

```json
"paymentGateway": {
  "id": "saleor.io.gift-card-payment-gateway",
  "data": {
    "code": "valid-gift-card-code"
  }
}
```

important

-   The channel currency must match the gift card currency.
-   The card can be used multiple times until the balance is depleted.
-   The card can be attached to only a single checkout at the time. Attaching gift card to another checkout will detach it from a previous checkout.
-   A card [restricted to a customer](#restricting-gift-cards-to-a-customer) can only be used by that customer, signed in. A guest checkout never matches, and a matching checkout email is not enough.

Restricted cards are rejected with the generic `Gift card code is not valid.` message, the same one returned for a code that does not exist, so the response never reveals whether a card exists or whom it belongs to. The check runs before the balance check, so a caller who is not the assignee never learns the card's remaining balance.

Example of using gift card to in a checkout. Notice `id` of payment gateway being set to `saleor.io.gift-card-payment-gateway`.

**Mutation**

```graphql
mutation transactionInitialize($id: ID!, $amount: PositiveDecimal!, $paymentGateway: PaymentGatewayToInitialize!) {
  transactionInitialize(id: $id, amount: $amount, paymentGateway: $paymentGateway) {
    transactionEvent {
      type
    }
    errors {
      field
      message
      code
    }
  }
}
```

**Variables**

```json
{
  "id": "Q2hlY2tvdXQ6MjcyYzYxOGItZGU3My00Zjc0LTllNzYtZDMzNGQ1ZThkMTk0",
  "amount": "3",
  "paymentGateway": {
    "id": "saleor.io.gift-card-payment-gateway",
    "data": {
      "code": "8554-B58D-06B9"
    }
  }
}
```

**Result**

```json
{
  "data": {
    "transactionInitialize": {
      "transactionEvent": {
        "type": "AUTHORIZATION_SUCCESS"
      },
      "errors": []
    }
  }
}
```

<a id="managing-gift-card-payments"></a>

### Managing Gift Card payments

<a id="creating-authorization-transactions"></a>

#### Creating Authorization Transactions

Successfully running `transactionInitialization` mutation results in creation of an authorization transaction.

<a id="updating-authorization-transactions"></a>

#### Updating Authorization Transactions

If gift card is already authorized to a checkout but `amount` has to be updated run `transactionInitialize` with adjusted `amount` value. Previous authorizations will be cancelled.

<a id="cancelling-authorization-transactions"></a>

#### Cancelling Authorization Transactions

Authorization transactions can be cancelled by either calling [`transactionRequestAction`](/api-reference/payments/mutations/transaction-request-action.md) with `CANCEL` action or by applying gift card to another checkout.

<a id="charging-transactions"></a>

#### Charging Transactions

When order gets confirmed Saleor attempts to charge funds from gift cards. If gift card has less funds than authorization transaction was initialized for the charge attempt will fail.

<a id="refunding-charge-transactions"></a>

#### Refunding Charge Transactions

For information about refunding charge transactions refer to [Refunds](/developer/payments/refunds.md).

<a id="legacy-using-gift-cards-in-checkout"></a>

## Legacy using Gift Cards in Checkout

warning

This flow is deprecated and **will** be removed in a future release.

You can disable legacy use of Gift Cards in Checkout by unsetting `allowLegacyGiftCardUse` flag in Channel's [Checkout Settings](/api-reference/checkout/inputs/checkout-settings-input.md) configuration.

<a id="applying-gift-cards"></a>

### Applying Gift Cards

To use a gift card in checkout, run the [`checkoutAddPromoCode`](/api-reference/checkout/mutations/checkout-add-promo-code.md) mutation with the gift card code.

important

-   The channel currency must match the gift card currency
-   The card can be used multiple times until the balance is depleted

<a id="tax-handling"></a>

### Tax Handling

Gift cards are applied to the checkout total after tax calculation:

1.  First, Saleor calculates all taxes for the order
2.  Then, the gift card amount is subtracted from the gross total price
3.  The net amount and tax amount are adjusted proportionally

<a id="multiple-gift-cards"></a>

### Multiple Gift Cards

When multiple gift cards are used:

-   Saleor will always try to use the full amount from each gift card
-   The system processes gift cards in the order they were added to the checkout
-   If the checkout total is less than the gift card amount, only the necessary portion will be used
-   The remaining balance stays on the gift card for future use

<a id="balance-changes"></a>

## Balance Changes

Gift card balances are only updated after the order is completed:

-   Adding card to the checkout does not modify the card balance
-   Used amount will be deducted during checkout completion
-   If an order is cancelled, the gift card balance is not restored
    -   You can restore current balance using [`giftCardUpdate`](/api-reference/gift-cards/mutations/gift-card-update.md)
    -   If you used Transaction API for applying gift card you can also [refund](#refunding-charge-transactions) gift card transactions

<a id="returns-and-refunds"></a>

## Returns and Refunds

important

Fulfilled gift cards cannot be returned or refunded. Once a gift card is fulfilled and sent to the customer, it cannot be reversed. This is because:

-   Gift cards are considered digital products
-   They can be used immediately after fulfillment

If a customer requests a return for a gift card product (i.e., the gift card code has not yet been used), you can handle the process manually:

1.  Refund the payment through your payment gateway
2.  Deactivate the associated gift card in the Saleor dashboard to prevent future use
