Gift cards hold purchased value issued by one merchant, in USD. They work only with that merchant and environment. Purchased cards have no expiry or fees. Promotional gift card products, customer store credit, transfers, and cross-merchant spending are not supported. To add unpaid value to a card, use a positive adjustment with reason complimentary.
You can issue, load, redeem, and reconcile cards without a Flint order. Hosted checkout uses the same ledger and can apply up to 20 cards alongside one processor payment. Gift card value pays the order after discounts and tax; it is not a discount. Gift card value cannot pay for subscription orders. Existing gift card value cannot fund a new gift card purchase. In a mixed basket, it can pay for eligible merchandise.
Save a card in a buyer account#
A buyer with a full customer session can save a card with POST /v1/me/gift-cards. The session determines the buyer, merchant, and environment; do not pass identity selectors. Reads and removal accept no request body. Provide one possession proof:
{ "credential_type": "code", "code": "GIFT_CARD_CODE" }
Or provide credential_type: "recipient_access", grant_id, and recipient_access_token from the original private recipient link. The grant ID is in the link's path and the token is in its fragment. Do not send both proof types or extra fields. Parse pasted links locally without fetching their URL, and keep codes and tokens out of navigation, browser storage, and telemetry.
Saving an active or frozen card, including one with no remaining balance, adds it to the buyer's saved collection. Several buyers may save the same card. Saving does not change customer_id, move funds, reveal the full code, or authorize checkout spending. Buying a card or matching its recipient email does not grant saved access. Order, invoice, return, and subscription sessions cannot use these endpoints.
GET /v1/me/gift-cards lists saved cards with current access. GET /v1/me/gift-cards/{gift_card_id} returns the card's masked identifier, status, balance, reserved amount, available amount, and timestamps. Existing saved cards remain readable after being frozen or closed. Replacing the code removes them from the list and makes detail and history reads return 404 until the buyer saves again with fresh proof. Expiry of the original private link does not expire previously saved access.
GET /v1/me/gift-cards/{gift_card_id}/transactions returns the full anonymous balance-change history, including changes made by other holders. Each entry includes its per-card sequence, signed amount, balance before and after, and posting time. Customer identities, order and payment references, source identifiers, reasons, and command keys are omitted.
Both lists take page_size and page_token, with a default of 20 and a maximum of 100. Cards sort by saved time, then card ID, descending. History sorts by per-card sequence, descending. Continue with the same page size and authenticated buyer. History tokens also require the same saved credential version.
DELETE /v1/me/gift-cards/{gift_card_id} removes only that buyer's saved access. Save and remove return 200. Duplicate saves do not add another entry, and repeated removals succeed. Both writes accept an optional Idempotency-Key, scoped to the buyer, merchant, environment, and operation. A replay cannot restore removed or revoked access. Removing and re-adding a card requires a new save key.
Issue and recover a card#
Create a card with currency: USD and optional funding. Unfunded cards remain pending. Funding records value_money, the face value issued, separately from consideration_money, the amount paid. external_payment funding requires a buyer_id for a customer in the environment, a reference_id, and consideration_money. import funding requires a reference_id; buyer_id and consideration_money are optional. Retire an imported balance in the source system so it cannot be spent in both places. References record activity outside Flint and do not mean Flint processed a payment. flint_payment funding requires a succeeded standalone payment intent from the same merchant, with enough unrefunded captured value to cover consideration_money. Manual-payment funding is created only through an order.
Money-changing commands require a caller-chosen Idempotency-Key. Retain and reuse the same key after a timeout. Replaying identical input returns the original operation; changing input with that key produces a conflict. Flint keeps the key for as long as the ledger exists, so a lost response can always be recovered by replaying the original request. Loads, redemptions, and transactions can also be listed with an idempotency_key filter.
Issuance and code rotation return the full code once. Replaying the same request returns it again for 24 hours; after that, a replay still returns the result without the code. Other reads, logs, and webhooks show only the last characters. The recipient's private access page is the only other place the full code appears. Store codes as credentials. Never put them in URLs or logs. Lookup uses a JSON request body. Code rotation revokes old credentials and recipient links while preserving balances and protecting already-reserved payments.
Codes have 16 normalized ASCII characters, for example 0000-0000-0000-0000 in a synthetic test. Lookup trims surrounding whitespace, ignores ASCII hyphens, accepts ASCII letter case, maps O to 0, and maps I and L to 1. It rejects Unicode and does not support prefix matching.
Reserve and redeem value#
balance_money is posted value, including reservations. reserved_money is held value; available_money is the spendable remainder. A freeze prevents new spending and retains the balance. Closing requires resolving remaining value and protected reservations. It cannot erase money.
Create a redemption with an amount, external reference, and capture_mode. Automatic capture posts the spend immediately. Manual capture creates a reservation that you later capture or cancel with an Idempotency-Key; add expected_version to reject a concurrent change. Reservations last 15 minutes by default and up to 24 hours. Expiry cannot release money behind a payment whose outcome is still unknown. Retrieve the existing redemption to recover its state before issuing another command.
Applying a card to an order returns an estimate. Accept the exact order revision, card allocations, and processor remainder when paying. Any change, up or down, returns GIFT_CARD_ALLOCATION_CHANGED; refresh the estimate and get the buyer's acceptance again. Gift-card-only payment settles without a processor charge.
Refunds and funding losses#
Refund merchandise through the refund API. Without tender_allocations, an order refund returns value to the original gift cards first; send allocations to choose gift card redemptions or processor payments yourself. Each original tender has a cumulative refund cap. The default destination restores the original card. If that card is closed or cannot accept the full allocation, explicitly authorize a replacement destination. Replacement value retains its funding provenance and risk restrictions; it does not become a newly paid load. Replays recover the same destinations.
Refunding a gift card purchase removes eligible unspent value from its funding load, including value restored through linked merchandise refunds. Spent or reserved value causes a conflict. Unknown provider refund outcomes remain protected until reconciled. Purchase refunds and manual-payment reversals do not use an ordinary balance adjustment to hide unavailable value.
After reversing a manual payment for a gift card purchase, collecting the outstanding amount through a processor or another manual payment restores the reversed value. The purchase keeps its original unit identities. If restoration requires a replacement card, purchased_gift_cards links it to the original card with restoration_reason: processor_recollection or manual_recollection, according to the new payment.
An open or lost dispute on a funding payment freezes the whole card. Value from other loads keeps its provenance but cannot be spent until the dispute is won or its loss is honored. Winning clears only that dispute's restriction. After a loss, create a gift card funding disposition with dispute_id, disposition: honor_value, and reason_message. Use commerce.gift_cards.adjustments.write and a durable Idempotency-Key. The 201 response returns the GiftCardFundingDisposition directly in data, including the disputed amount, original consideration, honored value, and preserved reservations. Unknown disputes return 404; disputes without an eligible funding loss return 409. Cash-out records require external payout evidence; recording one does not send cash to the buyer.
Recipient email#
Creating or rotating a card does not send an email unless you explicitly supply notification. Otherwise, create a notification with the card ID and recipient. Notifications use the current credential version and do not issue value, activate a card, or fulfill an order. Recipient email is required; name is optional, the message can contain up to 200 characters, and send_at can schedule up to 90 days ahead.
Status is scheduled, queued, sending, sent, failed, unconfirmed, bounced, or canceled. sent means the email provider accepted the message, not that the recipient opened it. For unconfirmed, the email provider did not confirm whether it sent the message. Flint does not resend it automatically. Retrieve the notification for its recent delivery.attempts and provider_outcomes. The history includes truncation flags when older records exist. After an outcome resolves, an explicit resend uses resend_of_notification_id and a new command identity. You can cancel a notification that is scheduled, queued, failed, or bounced. Once sending starts, cancellation returns a conflict. A notification for a pending card waits until the card is funded.
Recipient email opens private hosted access valid for 30 days from sending. Expiring or revoking that access does not expire the card's funds. Changing a credential revokes old access. Issuing and loading, spending, and adjustments and cash-outs have separate scopes. Recipient email and code replacement both require commerce.gift_cards.secrets.write; grant each scope only to callers that need it.
Reconcile#
List gift cards, loads, redemptions, and notifications with created_after and created_before to filter created_at. Use posted_after and posted_before on the merchant-wide transaction feed to filter posted_at. Both bounds are inclusive RFC 3339 timestamps. Money fields use the shared Money schema; transaction amounts and adjustment inputs use SignedMoney because they can be negative. Gift cards use USD.
Use the merchant-wide transaction feed to reconcile postings by card, source, order, period, or durable command key. Transactions are immutable and expose balance before and after each posting. Reservations and notification events do not change posted liability.
Subscribe to gift_card.*, gift_card_load.*, gift_card_notification.*, gift_card_redemption.*, and gift_card_transaction.created events. Set enabled_events to exact event names, such as gift_card_notification.created and gift_card_notification.updated, to receive only those events. Notification events carry a snapshot of the recipient, status, and notification version; retrieve the notification for current delivery history. Refunds appear as redemption, load, and transaction updates. Delivery is at least once and can arrive out of order. Deduplicate by event ID, compare resource versions, and retrieve current state when needed. Events never include full codes or recipient access secrets.
Use gift_card_liability_v1 for a fixed liability roll-forward and orders_itemized_v2 to separate gift card purchase consideration from merchandise. A $25 card sold for $22 adds $25 of face value and records $22 of consideration; its later redemption pays for merchandise. Do not count cash collected at issuance as another merchandise sale. See reports for report boundaries and columns.
Cash-out eligibility#
The merchant pays the customer outside Flint, then records the completed payout with the cash-out operation and its external evidence. A cash-out is a balance debit, separate from a merchandise refund or a refund of the card's purchase. Its amount cannot exceed unreserved value. Recording a larger voluntary payout is supported; these thresholds are eligibility floors, not maximum ledger debits.
State law sets the minimum: a remaining balance under the state's threshold must be paid out on request. Your policy can cover larger balances but not fewer. State rules include conditions and exclusions, and the state that governs an online sale needs legal review. The following table covers purchased, single-merchant cards and was checked on October 2, 2026.
| State | Remaining balance eligible on request | Conditions and source |
|---|---|---|
| California | Less than $15 | Operative April 1, 2026. Civil Code 1749.5 |
| Colorado | $5 or less | Single-merchant cards. C.R.S. 6-1-722 |
| Connecticut | Less than $5 | After a purchase; the statute has exclusions, including some discounted cards and out-of-state retailers. Consumer protection guidance |
| Hawaii | Less than $5 | Consumer protection guidance |
| Maine | Less than $5 | After an in-person redemption; original value must exceed $5. 33 M.R.S. 2067 |
| Massachusetts | $5 or less for a reloadable card; otherwise after at least 90% of its value has been redeemed | Retail rights guide, gift certificate guidance |
| Montana | Less than $5 | Original value must exceed $5. MCA 30-14-108 |
| New Jersey | Less than $5 | After redemption. Cash balance redemption guidance |
| New York | Less than $5 | Division of Consumer Protection guidance |
| Oregon | $5 or less | Most cards after a purchase; consult the linked guidance for exceptions. Department of Justice guidance |
| Rhode Island | Less than $1 | Remaining value after redemption. R.I. Gen. Laws 6-13-12 |
| Vermont | Less than $1 | 8 V.S.A. 2704 |
| Washington | Less than $5 | Remaining value after a purchase. RCW 19.240.020 |
Checkout credential verification#
Failed gift card guesses are counted independently for the checkout session, client IP and merchant environment. Each count runs for one hour from its first failure. After five session failures, ten IP failures, or fifty merchant failures, every checkout lookup in that hour requires a fresh Cloudflare Turnstile challenge for action gift_card_code, even with a valid code. Send its token in Flint-Gift-Card-Challenge. The challenge is separate from the spending code and is never part of the financial command identity. Hosted checkout shows the challenge when it is required. Buyers get the same GIFT_CARD_UNAVAILABLE refusal for unknown, other-merchant, and inactive codes.
A dashboard session must have verified its strongest available sign-in factor within the last five minutes to send a recipient email, issue a card with notification, or replace a code. Creating or updating an API key, approving CLI access, or authorizing a partner installation with commerce.gift_cards.secrets.write or accounts.api_keys.write requires the same verification; developer email sessions verify by email. The dashboard prompts and retries for API keys and CLI access. Other session callers receive 403 GIFT_CARD_RECIPIENT_VERIFICATION_REQUIRED; verify again, get a new token, and retry with the same Idempotency-Key. Refreshing a token alone does not renew verification. API keys and installed integrations are not challenged.
In a dashboard session, merchant viewers can read gift cards, and order operators can also redeem, capture, and cancel reservations. Every other gift card command, including updates, freezes, closing, honoring a funding loss, and canceling notifications, requires a merchant administrator or owner. Fresh verification preserves these role requirements.
Purchase velocity limits#
Processor-funded gift card purchase attempts have separate daily face-value limits for the buyer email, the payment card fingerprint on card, Apple Pay, and Google Pay payments, and the device when one is sent. Each defaults to $10,000 per merchant environment and UTC day. The platform can lower each limit. Failed attempts count toward the limit; exact retries of the same attempt count once. Split payment legs each count the full face value of gift cards that have not yet been issued, including partially funded cards, so a split purchase can reach the limit sooner. Value awaiting restoration after a manual-payment reversal also counts. Already-issued cards do not count again toward unrelated merchandise payments. The existing card balance and funding limits still apply.
For checkout-session purchases, send Flint-Buyer-Device with a stable random 32-character lowercase hexadecimal device identifier. Keep it across orders on the same device. A checkout-session purchase without it returns GIFT_CARD_BUYER_DEVICE_REQUIRED. Hosted checkout supplies it from a secure, HttpOnly cookie, separate from checkout credentials. This identifier is a fraud signal and grants no access. Clearing cookies or changing device identifiers can reset that signal; payment card and buyer email controls remain independent. Merchant integrations can supply the same header when they have a buyer device. Standalone flint_payment creation and reloads apply these limits before adding gift card value, using the captured payment's original card, buyer email, and device identities. A standalone payment may already have charged its buyer before you choose to allocate it to a gift card. If allocation is refused, refund that payment or use it for its original purpose. Manual, imported, and external attested funding retain the funding limits and audit requirements; they do not claim a processor card identity.
Card fingerprints come from the processor, and the buyer email comes from the Flint customer bound to the payment. Caller-supplied billing or receipt emails do not replace that buyer identity. For order purchases, a missing fingerprint on a card-backed payment, a missing required device identifier, or an unavailable verification service rejects the purchase before charging. GIFT_CARD_PURCHASE_LIMIT_EXCEEDED means this purchase would exceed a limit for the current UTC day. A smaller purchase can still fit, and a single purchase above a limit is always rejected.
