Let shoppers pay with a gift card or store credit through commercetools Checkout, and build the Connector that checks balances, redeems value, and returns it after an Order.
Nothing in the platform stops you from configuring a gift card Payment Integration on its own. The misconfiguration isn't rejected when you save it, and the failure appears at the shopper's checkout instead. That's why this rule sits here rather than in troubleshooting.
The rule also constrains the Connector you build. A redeem operation must never reject a card because its balance is lower than the Cart total. Redeeming less than the total is the expected case, and the other Payment Integration collects the remainder. A Connector that treats a short balance as an error removes the behavior the fallback exists to provide.
This guide owns the integration decision and the Connector build. The reference material lives in the Checkout documentation, and this guide links to it rather than repeating it:
- the gift card Connector contract
- the gift card Messages
- rendering and Message handling in the Browser SDK
- the Payment Intents API
Before you begin, make sure you have the following:
- a commercetools Project
- access to Connect
- a Checkout Application that already has at least one working Payment Integration
- credentials for a gift card system test environment
- a backend route that creates the Checkout Sessions these flows depend on, as described in Installing Checkout
Define the gift card requirements
Each decision below becomes a configuration value, a Connector capability check, or a Checkout Application setting. Document them before you select or configure a Connector.
- Gift card system: identify the system, the account environment, the credentials, and the balance and redemption operations it exposes.
- Currency scope: record every currency the storefront sells in. This is the first of two decisions that break checkout when you get them wrong. For the reason, see Scope the deployment to a currency.
- Fallback Payment Integration: name the other Payment Integration that collects the remainder, and confirm that it's deployed and configured on the same Checkout Application. This is the second decision that breaks checkout when you get it wrong, and it's the rule stated at the top of this guide.
- Card presentation: decide whether the shopper enters a code alone or a code and a PIN, and what validation the storefront applies before the code reaches the Connector.
- Partial redemption and multiple cards: decide whether one Cart can carry several cards, and whether a card can be redeemed for less than its balance.
- Expiry and zero balances: decide what the shopper sees for an expired card and for a card with no remaining value. Both are valid card states, not errors in the integration.
- Post-order operations: decide whether a refund returns value to the original card, and whether a failed Order requires a full reversal. Your answers determine which operations the Connector must support.
- Region, Project, and Stores: record these, along with any multi-Store or business-to-business requirements.
- Anything else: record constraints that no fixed list asks about, such as a card that's also a loyalty instrument, breakage reporting, a card issued by a franchise partner, or a balance shared with a point-of-sale system. Each of these can move the decision in the next section from configure to build.
Confirm this list with the business before you derive any configuration. A requirement recorded late in this domain usually changes the Connector rather than a setting.
Choose an integration path
Check the live Connector catalog
view_connectors scope to call the Search Connectors endpoint, and filter on the giftcard IntegrationType.GET https://connect.{region}.commercetools.com/connectors/search?integrationTypes=giftcard&private=false
private=false so that the results include Connectors that aren't yet assigned to your Project. For the host to use in each Region, see Hosts and authorization. Record the Connector key, the version, and the date you checked.Assess the available options
Three options exist, and they differ in what they leave you to build.
| Option | State when checked on 2026-09-11 | What it means for your project |
|---|---|---|
| Sample gift card Connector | A Public Connector installed from the marketplace. It simulates gift cards and settles nothing. The documentation for its test codes closes with the sentence "These values are for simulation purposes only; no payment is actually made." See Sample gift card Connector. | Use it to prove that a Checkout Application renders a gift card Payment Integration and that the fallback method collects a remainder. Never use it as evidence that an integration works. |
commercetools/connect-giftcard-integration-voucherify, commit 55d620d | An open-source Connector maintained by commercetools for Voucherify. Latest commit dated 2026-07-29. | The one production gift card system with a public Connector. It pins a deployment to a single currency, takes hand-supplied commercetools credentials, and declares no lifecycle scripts. |
commercetools/connect-giftcard-integration-template, commit b3b4789 | The gift card integration template. Latest commit dated 2026-09-03. | The starting point for every other gift card system. It implements the full Checkout contract against a mock gift card client, described in Replace the simulated gift card client. |
/connect/templates page exists for the gift card template, so the repository itself is the reference.Most gift card systems are a build-from-template job. Budget the project on that assumption unless your catalog check finds a Connector for your specific system.
Choose the first path that fits
- Install and configure a Public Connector when its published contract covers your requirements. For Voucherify, this is the whole job.
- Prove that configuration can't close the gap before you change any code. Gift card Connectors commonly expose the system base URL, the account credentials, the currency, and the Payment interface name as configuration.
- Fork an open-source Connector when the gap is genuine. The Voucherify Connector is open source, so a system with a similar balance-and-redeem API is often closer to a fork than to a fresh build. A fork keeps the Session authentication, the Payment ownership model, and the route contract that already work.
- Build from the gift card integration template when no Connector exists for your system, which is the common case.
commercetools connect validate
Record the option you chose and the reason. Rebuilding a Connector that already exists is the most expensive way to obtain one.
Design the two applications
A gift card Connector declares two Connect applications. The split decides where secrets live and which credential authenticates each call.
- The processor is a
serviceapplication. It holds the gift card system credentials, calls the system, and owns the commercetools Payment. - The enabler is an
assetsapplication. It delivers the browser-facing library that renders the gift card input inside Checkout.
Separate the enabler from the processor
The enabler delivers the browser-facing library as static assets, and it keeps the gift card system credentials out of the browser. It holds no secrets, makes no call to the gift card system, and authenticates to the processor with the Checkout Session rather than with an API token.
Keep every credential in the processor. The enabler is served to the browser, so a value placed there is public. The payment integration template documents a reduction in Payment Card Industry compliance obligations for its own enabler. That claim covers cardholder data, it doesn't transfer to a gift card code, so don't rely on it here.
Authenticate each route correctly
401 on exactly one flow while the others work, which looks like a defect in the failing flow rather than in the wiring.| Route | Caller | Authentication | Additional authorization |
|---|---|---|---|
POST /balance | The enabler, in the browser | Checkout Session | None |
POST /redeem | The enabler, in the browser | Checkout Session | None |
POST /payment-intents/:id | Checkout, on behalf of a merchant operation | OAuth 2.0 access token | The token is authorized against manage_checkout_payment_intents |
GET /status | Merchant Center health checks | Merchant Center JSON Web Token | None |
Treat this table as the contract of the Connector you deploy. Wire each route to its own model rather than to one shared mechanism, and cover each route with a test that asserts the rejection as well as the acceptance.
expiryAt, and it can expire while the shopper is still on the payment step. The balance and redeem routes must therefore reject an expired Session cleanly and let the storefront obtain a new one, rather than failing part way through a redemption. See Create Checkout Sessions.Keep balance read-only and redeem idempotent
Balance is a read. It must not reserve, hold, or deduct value. Checkout calls it while the shopper is on the payment step, so a balance call with a side effect makes the card shrink every time the shopper looks at the page.
Redeem moves money, so it must be idempotent. Key it on the card code together with the Cart or Payment context. A replay of the same request then returns the first result, while a second, different card is still redeemed on its own. Reconcile against the Payments already attached to the Cart before you create another one.
Neither the gift card integration template nor the Voucherify Connector implements this. In both, a replayed redeem creates a second Payment and charges the card again. This is work you own, and it stays invisible until production traffic produces the first retry.
Configure the Connector
connect.yaml. Two placement rules have silent failure modes:connect.yamlsits at the root of the Connector, above application folders such asprocessorandenabler, rather than inside one of them. A nested file isn't found, and the Connector never appears.- The
endpointvalue an application declares inconnect.yamlsets the path that Connect appends to the deployment URL. Both current gift card Connectors serve the processor at the root of that URL, and Checkout calls the route paths in the contract directly. A processor that declares an extra path segment therefore answers a direct request while every Checkout call returns a not-found response.
Set the Region-specific values
The authorization host, the API host, the Session host, the JSON Web Key Set URL, and the token issuer are all Region-specific, and a Connector default often points at one Region. This misconfiguration has no deployment-time signal. The deployment succeeds and reports healthy, and then every call fails authentication.
Scope the deployment to a currency
400 response carrying a currency-mismatch key. The check runs in the balance operation as well as the redeem operation, so the shopper sees the failure at the first interaction.100 Payment Integrations on an Application.Create the API Client
inheritAs.apiClient.scopes block, so Connect doesn't generate a runtime client for you. Create the API Client before the deployment, and supply its identifier and secret as configuration.The processor built from the template runs a health check that fails unless the client holds all of the following scopes:
manage_payments, because the processor creates the Payment and writes its Transactions.manage_orders, for the Cart and Order operations the redeem flow performs.view_sessions, to validate the Checkout Session that the enabler presents.view_api_clients, which the health check reads.manage_checkout_payment_intents, for the post-order operation route.introspect_oauth_tokens, to validate the OAuth token on that route.
manage_api_clients isn't required here, because these Connectors don't generate their own credentials.invalid_scope error at authentication rather than a permission error at the failing call, which sends you looking in the wrong place.Separate secured and standard configuration
securedConfiguration. Values in standardConfiguration are readable, so keep only non-secret settings there, such as the hosts, the Project key, the client identifier, the currency, and the Payment interface name.Add lifecycle scripts if your system needs them
scripts: block in connect.yaml. Connect never invokes a connector:post-deploy or connector:pre-undeploy command that's defined in package.json alone, so the script appears to be ignored. If your gift card system requires registration at deployment or teardown at undeployment, add the scripts: block that names those commands.Configure the fallback Payment Integration
The rule at the top of this guide is also a configuration step. On the Checkout Application that carries the gift card Payment Integration, confirm that at least one other Payment Integration is configured and enabled, and that it covers the same currencies and Regions as the gift card deployment.
Verify this in the Application configuration rather than inferring it from the storefront, because the gift card path renders correctly whether or not a fallback exists. The absence shows only when a balance falls short.
Implement the gift card flows
Replace the simulated gift card client
Charge Transaction, and completes an Order, all without contacting a gift card system.This is the same trap as the sample Connector, reached by a different route, and it's more dangerous because the build looks like your own work. Replace the mock client with a client for your gift card system before you treat any verification result as evidence. Until you do, a green end-to-end run proves only that the Checkout contract is wired.
Keep the replacement behind the same interface the template defines. The route handlers, the Payment writes, and the currency guard then stay unchanged, and the tests keep a boundary to mock.
Check the balance
Balance answers a question and persists nothing. The contract is as follows:
- The enabler collects the code, and the PIN when the system requires one, and calls
POST /balancewith the Checkout Session. - The processor reads the Cart that the Session identifies and derives the payable amount from it.
- The processor compares the Cart currency against the deployment currency and stops with a
400response on a mismatch. - The processor calls the gift card system's balance operation with the system credential.
- The processor returns the amount and whether it covers the payable amount.
GiftCardBalanceSuccess or GiftCardBalanceError Message, and the success payload carries the amount and a flag stating whether the balance is sufficient.Treat an expired card and a card with a zero balance as successful reads that report an unusable card, rather than as failures of the balance operation. The shopper needs a message, not an error page.
Redeem value onto a Payment
Redeem is where the processor takes ownership of the commercetools Payment. Your own backend must not create Payment objects for gift cards. A second Payment for one attempt breaks the remainder arithmetic that the fallback method depends on.
The gift card integration template and the Voucherify Connector both implement the sequence below. This is the behavior of those Connectors rather than a documented platform guarantee, so confirm it against the Connector you deploy.
- The enabler calls
POST /redeemwith the code and the amount to redeem, authenticated by the Checkout Session. - The processor reads the Cart and applies the currency guard.
- The processor performs the idempotency check described in Keep balance read-only and redeem idempotent, and returns the earlier result when this request is a replay.
- The processor creates a Payment whose
amountPlannedis the amount being redeemed, not the Cart total, and whosepaymentMethodInfoidentifies the Connector and the gift card method. - The processor attaches the Payment to the Cart. This update uses the Cart version it just read, so a stale version produces a ConcurrentModification error.
- The processor calls the gift card system's redeem operation and receives a redemption reference.
- The processor adds a
ChargeTransaction to the Payment, using the Payment version returned by the create call. The Transaction carries the redeemed amount, the redemption reference as the interaction identifier, and a state mapped from the system result.
Two consequences of this sequence matter for failure design. First, the Payment exists before the gift card system is called, so a system failure leaves a Payment without a successful Transaction, and your monitoring must be able to recognize that. Second, every step operates on a Cart, so value leaves the card before the Order exists. Checkout creates the Order later in the flow, so a design that assumes an Order is present whenever value has moved is wrong.
amountPlanned to the redeemed amount is also the mechanism for partial redemption. It isn't a separate feature to implement.Handle partial redemption and multiple cards
Charge Transaction, and the amount redeemed from card two is the lesser of its balance and the amount still outstanding. The balance check for card two is evaluated against the outstanding amount rather than against the original Cart total. Carts therefore accumulate Payments rather than accumulating Transactions on one Payment, and reconciliation must read all of them.The default shopper-facing text in Checkout promises a reimbursement when the fallback method fails after a gift card was already redeemed. That text is a configurable default stored under a generic second-payment-method error key, not a documented reimbursement mechanism. Confirm the behavior against your Connector's refund implementation during verification, because the reimbursement depends on the Connector supporting the operation.
Implement refund and reversal
POST /payment-intents/:id route with an OAuth token authorized against manage_checkout_payment_intents. This route is neither Session-authenticated nor reachable from the enabler.- Refund returns value to the card. Write the
RefundTransaction before the external call, and update its state from the system result, so that an ambiguous timeout leaves a record to reconcile. See Refund Payment. - Reversal returns the full planned amount. Automated Reversals cancel or refund a Payment when Order creation fails, and they work only when the Connectors in the Project support Reverse Payment. A gift card Connector that omits it removes that safety net for every Payment on the Cart.
- Capture and cancellation are a Connector implementation choice rather than an API restriction. The Payment Intents API defines both actions for a payment service provider or a gift card management system. A gift card redeems rather than authorizing and capturing later, so both current gift card Connectors answer these operations with an unsupported response. That response is correct behavior, even though it looks like an unimplemented feature.
Surface results in the storefront
Verify and operate the integration
sandbox deployment scales to zero when it's unused and needs about 15 seconds to boot again, so the first balance or redeem call after an idle period can appear to hang. The diagram below shows the round trip that the checks assert.Work through these checks in order:
- Verify the configuration. Confirm that every host matches the Project Region, that the deployment currency matches the test Cart, that secrets appear only in secured configuration, and that the Checkout Application carries the fallback Payment Integration.
- Verify that balance is a read. Check the balance of a card twice without redeeming. The amount is identical both times, the gift card system records no reservation, and the Cart carries no Payment.
- Verify a full redemption. Redeem a card that covers the Cart. The Cart carries exactly one gift card Payment, its
amountPlannedequals the redeemed amount, and it holds one successfulChargeTransaction that carries the system's redemption reference. - Verify a partial redemption. Redeem a card worth less than the Cart total. The outstanding amount equals the Cart total minus the redeemed amount, the shopper is offered the fallback Payment Integration, and paying it produces a second Payment on the same Cart.
- Verify multiple cards. Apply two cards to one Cart. Two Payments exist, each with its own
ChargeTransaction, and the second card was redeemed for the outstanding amount rather than the original Cart total. - Verify the Order. Confirm that exactly one Order exists and that it references every Payment created during the attempt.
- Verify a replay. Send the same redeem request twice. One Payment exists, one
ChargeTransaction exists, and the gift card system records one redemption. - Verify refund and reversal. Refund a gift card Payment and confirm both the
RefundTransaction and the value returned in the gift card system. Then confirm that the Connector answers the reverse operation, because Automated Reversals depend on it. - Verify the shortfall failure. Fail the fallback method after a gift card was redeemed, and confirm that the reimbursement your Connector performs matches what the shopper was told.
- Verify unusable cards. Present an expired card and a card with a zero balance. Each produces a shopper-readable message and leaves the Cart unchanged.
Once live, monitor Payments that hold no successful Transaction, redeem retries, currency-mismatch responses, authentication failures per route, and Connector deployment health. Log the Cart identifier, the Payment identifier, and the gift card system's redemption reference together, because that record is what answers a balance query from finance.
Test with the simulated codes
Valid-{amount}-{currency}, with variants that force a failed payment and a zero balance. Use them to exercise the Checkout Application, the Payment Integration configuration, and the fallback path.500. Currencies without a minor unit, such as JPY, use the major unit. A test written as Valid-100-EUR therefore provides one euro rather than one hundred.These codes settle nothing. The documentation states that the values are for simulation purposes only and that no payment is made. A passing run with them is evidence about your Checkout configuration, and about nothing in your gift card system.
Diagnose common failures
Several correct behaviors in this domain look like defects.
| Symptom | Likely cause | Resolution |
|---|---|---|
| Every call to the processor fails authentication, although the deployment reports healthy. | A host, the JSON Web Key Set URL, or the issuer points at a Region other than the Project's. | Set every Region-specific value from the Region tables and redeploy. Check this first, because the failure has no deployment-time signal. |
Balance and redeem work, but the refund operation returns 401. Or the reverse pattern. | One route is wired to the wrong authentication model. | Match each route to Authenticate each route correctly. Session for balance and redeem, OAuth with manage_checkout_payment_intents for payment intents, and a Merchant Center token for status. |
| Every Checkout call returns a not-found response, although the processor answers a direct request. | The endpoint declared for the processor adds a path segment that Checkout does not call. | Align the declared endpoint with the route paths Checkout calls and redeploy. |
| The Connector never appears after deployment. | connect.yaml sits inside an application folder such as processor or enabler rather than above them at the root of the Connector. | Move the file to the root of the Connector and redeploy. |
Redeem fails with a 400 currency-mismatch response for shoppers in one country. | The Cart currency differs from the currency the deployment is pinned to. | Deploy one Connector and one Payment Integration per currency, or remove the check in your own build. |
| A valid card with money on it is refused. | The Connector rejects a balance lower than the Cart total. | Redeem the available amount and let the fallback Payment Integration collect the remainder. |
| The card balance shrinks each time the shopper opens the payment step. | The balance operation reserves or deducts value. | Make balance a read with no side effect. |
| A shopper double-clicked and the card was charged twice. | Redeem is not idempotent, so the replay created a second Payment. | Key redeem on the code and the Cart or Payment context, and reconcile against the Payments already on the Cart. |
| The gift card is applied and then the shopper cannot finish paying. | No other Payment Integration is configured on the Checkout Application. | Configure a fallback Payment Integration covering the same currencies and Regions. |
Checkout completes, an Order is created, and the Payment holds a Charge Transaction, but the gift card system shows no redemption. | The sample Connector is installed, or a template-based Connector still uses the mock gift card client. | Replace the mock client with a client for your gift card system, then repeat the verification. |
| Capture or cancellation returns an operation-not-supported response. | Expected. Gift cards redeem rather than authorizing and capturing. | Use refund and reversal for post-order operations. |
A lifecycle script defined in package.json never runs. | connect.yaml declares no scripts: block, so Connect never invokes it. | Add the scripts: block that names the commands. |
| Attaching the Payment to the Cart fails reporting a different version than expected. | The Cart changed between the read and the update. | Read the Cart immediately before the update and use the version it returns. |
| Deployment fails with an access-denied error, or the health check fails after deployment. | The API Client is missing one of the scopes the Connector definition requires. | Create a new API Client holding the complete set, because scopes cannot be changed after creation. |
Extend to another gift card system
Adding a second gift card system doesn't change the architecture. The two applications, the route contract, the authentication models, the Payment ownership, and the flows stay as described here. What changes is the client that talks to the system, the configuration that addresses it, and a second deployment with its own Payment Integration on the Checkout Application.