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

# Purchase Gift Card

Once you've determined your preferred offer, use the `purchaseGiftCard` mutation to purchase your gift card. This mutation requires a `PurchaseGiftCardInput` input object.

## Sample Mutation

Here's the quickest way to start purchasing a gift card. You are able to customize your query from the `UserPurchase` object. See the [API reference](https://storage.googleapis.com/fluz-public-docs/api-reference.html).

```graphql theme={null}
mutation purchaseGiftCard($input: PurchaseGiftCardInput!) {
  purchaseGiftCard(input: $input) {
    purchaseDisplayId
    purchaseAmount
    giftCard {
      giftCardId
      status
      termsAndConditions
    }
  }
}
```

## Fields

The following fields are used to run this mutation:

`idempotencyKey` — *Required.* A unique client-generated UUID to ensure a request is processed only once.

`offerId `**or** `merchantSlug` — *Required.* Use the `offerId` or `merchantSlug` from the [`getOfferQuote`](/get-best-offer) query to get the best offer. Using the `merchantSlug` will automatically purchase the best offer rate for that merchant.

`amount` — *Required.* The gift card amount you'd like to purchase.

***

Only one of the following is required. You may also choose to combine your Fluz balance with another funding source.

`exclusiveRateId` — The unique identifier for a specific exclusive rate offer. When provided, this forces the purchase to use the specified exclusive rate. If not provided, the system will automatically select the best available rate. The `exclusiveRateId` can be found in the [`getMerchants`](/get-catalog) query response for offers with type `EXCLUSIVE_RATE_OFFER` when you provide `exclusiveRateId` in your query request under `offers`.

`balanceAmount` — If you want to pay for your gift card with your Fluz balance, define the amount of balance here. You can use the [`getWallet`](/check-account-balance) query to check your balances.

`bankAccountId` — If you want to pay with a bank account, define the bank account ID.

`bankCardId` — If you want to pay with a bank card, define the bank card ID.

`paypalVaultId` — If you want to pay with a PayPal account, define the PayPal account ID.

`defaultToBalance` — If you want to use your Fluz balance as the fallback payment method in case your other payment methods fail, set `defaultToBalance` to `true`. By default, this is set to `true`. If you change this setting to `false`, the system will not attempt to use your Fluz balance as a backup payment method.

`minRewardRate` — If you want to specify the minimum reward rate to purchase if the `merchantSlug` option is chosen.

`userCashBalanceId` — If you want to specify the cash balance (spend account) to be used for that purchase.

`memo` — If you want to attach a note to this transaction, provide a free-text memo here. Max 255 characters.

`transactionCategory` — If you want to categorize this transaction, provide a category name. Categories are created automatically on first use and reused if the same name is passed again.

`attachmentId` — If you want to attach a file to this transaction, provide the ID returned by the upload endpoint. See [Add Expense Details](/features/add-expense-details).

<Callout icon="📘">
  ### See [Add Expense Details](/features/add-expense-details) for full details on uploading attachments and working with memos and categories.
</Callout>

## PurchaseGiftCardInput

```json theme={null}
{
  "idempotencyKey": "0284be6f-1a69-44f7-9da0-5b5edaf45d19",
  "offerId": "0284be6f-1a69-44f7-9da0-5b5edaf45d19",
  "amount": 987.65,
  "balanceAmount": 123.45,
  "bankAccountId": "0284be6f-1a69-44f7-9da0-5b5edaf45d19",
  "bankCardId": "0284be6f-1a69-44f7-9da0-5b5edaf45d19",
  "paypalVaultId": "0284be6f-1a69-44f7-9da0-5b5edaf45d19",
  "exclusiveRateId": "0284be6f-1a69-44f7-9da0-5b5edaf45d19",
  "merchantSlug": "xyz789",
  "minRewardRate": 5.6,
  "userCashBalanceId": "85de1b3e-4e72-462c-8ed1-a6f4982e22f7"
}
```

## Sample Response

Once your purchase is complete, you'll get a response that looks something like this:

```json theme={null}
{
  "data": {
    "purchaseGiftCard": {
      "purchaseId": "255f8245-02c7-4817-901e-15fe265f6968",
      "purchaseDisplayId": "1019688",
      "purchaseBankCardId": "255f8245-02c7-4817-901e-15fe265f6968",
      "bankAccountId": "255f8245-02c7-4817-901e-15fe265f6968",
      "purchaseAmount": 123.45,
      "fluzpayAmount": 85.0,
      "seatRewardValue": 0.05,
      "paypalVaultId": "255f8245-02c7-4817-901e-15fe265f6968",
      "createdAt": "2007-12-03T10:15:30Z",
      "giftCard": {
        "giftCardId": "85de8b3e-4e72-462c-8ed1-a6f4982e22f7",
        "purchaserUserId": "85de8b3e-4e72-462c-8ed1-a6f4982e22f7",
        "endDate": "2007-12-03T10:15:30Z",
        "status": "ACTIVE",
        "termsAndConditions": "Except as required by law, Gift Cards cannot be transferred for...",
        "createdAt": "2007-12-03T10:15:30Z",
        "merchant": {
          "merchantId": "85de8b3e-4e72-462c-8ed1-a6f4982e22f7",
          "name": "Starbucks",
          "slug": "starbucks",
          "logoUrl": "https://storage.googleapis.com/.../starbucks-logo.jpg",
          "faceplateUrl": "https://storage.googleapis.com/.../starbucks-faceplate.png",
          "offers": [
            {
              "offeringMerchantId": "85de8b3e-4e72-462c-8ed1-a6f4982e22f7",
              "offerId": "85de8b3e-4e72-462c-8ed1-a6f4982e22f7",
              "type": "GIFT_CARD_OFFER",
              "deliveryFormat": "CODES",
              "barcodeType": "C128",
              "hasStockInfo": false,
              "offerRates": [
                {
                  "maxUserRewardValue": 5.0,
                  "cashbackVoucherRewardValue": 1.0,
                  "boostRewardValue": 0.5,
                  "displayBoostReward": true,
                  "denominations": [25, 50, 100],
                  "allowedPaymentMethods": ["CREDIT_CARD", "PAYPAL"]
                }
              ],
              "denominationsType": "VARIABLE",
              "stockInfo": []
            }
          ]
        }
      }
    }
  }
}
```

<Callout icon="🚧">
  ### **Cashback rates are subject to change.**

  We do our best to always give our customers the best offers available. This means that our rates change regularly. Always confirm the rate before making a purchase.
</Callout>

## Buying more than one card

A single `purchaseGiftCard` call buys exactly one gift card, on one offer, at one rate. There is no quantity field, and a call is never split or blended across offers or rates. To buy several cards, send the mutation once per card, each with its own unique `idempotencyKey`.

Because each card is its own call, ordering more cards than a stocked offer has in inventory resolves per call:

* `offerId `**(pinned offer):** once the stocked offer is depleted, the remaining calls fail with `GC-0009`. There is no automatic fallback to another offer or rate.
* `merchantSlug `**(auto-select):** the remaining calls auto-select the next-best available offer — often a variable offer at a lower reward rate — unless `minRewardRate` blocks the lower rate.

For the full per-call breakdown, the `minRewardRate` rate-floor pattern, and the `GC-0009` response, see [Purchase in Bulk](/purchase-in-bulk).

### Ordering at volume: concurrency, timeouts, and retries

Purchases that draw on the same Fluz account are processed sequentially. When many `purchaseGiftCard` calls are submitted at the same time against a single account, they queue behind one another, and individual calls can take longer to return — occasionally up to a few minutes under heavy load. Calls that aren't queued typically return within seconds.

To keep latency predictable and avoid false failures when ordering at volume:

* **Pace your concurrent requests.** Instead of firing an entire batch simultaneously against one account, submit in smaller waves, or spread volume across multiple accounts. This keeps per-call latency low.
* **Use a generous client timeout.** Fluz does not abandon an in-flight purchase after a few seconds — a request can still be legitimately processing and will return a valid result. A short client-side timeout (for example, 30 seconds) may cause you to give up on a purchase that ultimately succeeds. Set your timeout high enough to absorb occasional multi-minute processing under load. We recommend 1 minute.
* **A client timeout is not a cancellation.** Closing your connection does not cancel a request that Fluz has already accepted; it continues processing to completion. Treat a timeout as an *unknown* outcome, not a failure.
* **Resolve timeouts by retrying with the same** `idempotencyKey`**.** Reissue the identical request with the identical `idempotencyKey`. Because the key guarantees the purchase is processed at most once, the retry returns the original purchase if it already succeeded — it will not create a duplicate or a second charge. Never issue a new `idempotencyKey` for a purchase you've already attempted; doing so is what produces duplicate orders.

<Callout icon="📘">
  ### If a purchase timed out on your side and you're unsure of its outcome, **retry with the same** `idempotencyKey`**, or look up the purchase by its purchase ID, before refunding the end user.** A timed-out request has often already succeeded on Fluz's side, and the gift card code remains revealable until the purchase is refunded.
</Callout>

## Next Steps

Now it's time to reveal your gift card details for use. Learn how to do so here:

[View Gift Cards](/view-gift-card)
