Build a redeemables payment extension
Redeemables payments extension enable merchants to integrate their external gift card provider as a payment method at checkout. Your payment extension enables customers to apply gift cards directly on the checkout page, without having to redirect them to an offsite page.
Your payments extension will provide a Checkout UI extension and Balance Request endpoint to enable Shopify to check the balance of gift cards during checkout.
Step 1: Scaffold an app
Anchor link to section titled "Step 1: Scaffold an app"To build a redeemables payments extension you will need to create a new app, with a redeemables payments extension and Checkout UI extension correctly applied.
Create your new app using the Shopify CLI.
Step 2: Create a Checkout UI extension
Anchor link to section titled "Step 2: Create a Checkout UI extension"After creating your app, generate a Checkout UI extension and deploy your app to Shopify. This extension will be used to collect gift card details from buyers directly on checkout.
- Use the Shopify CLI to scaffold a Checkout UI extension for your app.
- Name your extension
- Choose to work in TypeScript React.
- After you generate the extension, deploy your app to Shopify Partners. This will allow you to link the Checkout UI extension with your payments app extension.
- In Shopify Partners, click Apps.
- Select your app.
- Click Extensions. At this point, you should have the Checkout UI extension you created.
- Click the name of your Checkout UI extension.
- Follow this guide to create and release a new version of your app.
Step 3: Create a payments extension
Anchor link to section titled "Step 3: Create a payments extension"Generate the extension
Anchor link to section titled "Generate the extension"Your Shopify app becomes a payments app after you've created and configured your payments extension.
Redeemables describes a payment method that can be redeemed. Examples are gift cards, store credit, etc.
Run the following command to start generating your payment extension:
When prompted, choose your organization & create this as a new app
When prompted for "Type of extension", select "Payments App Extension > Redeemable" and name your extension
Set up your payments extension
Anchor link to section titled "Set up your payments extension"In this section, you will configure and deploy your application with the payments extension.
Disable embedding
Shopify apps are embedded by default, but payments apps are an exception to this, because they don't need to render anything in Shopify admin. In
shopify.app.toml
, update theembedded
and set it to false.Configure basic app settings
In
shopify.app.toml
, update thename
andclient_id
to match the information about the app that you manually created. You can find theclient_id
in the Client credentials section of you app's overview page in the Partner Dashboard.Push the configuration changes to your app and start your server
In a terminal, run the following commands to push the configuration changes to your app:
- Install the packages required to run the payments app:
shopify.app.toml
:Start your development server
To run the app locally, start your development server:
You might be prompted to log in to your Partner account. In your terminal, select your development store. You can use the generated URL to test your payments app by using it in your payments app configuration. If you want a consistent tunnel URL, then you can use the
--tunnel-url
flag with your own tunnel when starting your server.Press
p
to open the app in your browser. This brings you to your development store's admin, where you can install your payments app.
Step 4: Configure your payments extension
Anchor link to section titled "Step 4: Configure your payments extension"Configuration of a redeemables payments extension is similar to a Offsite payments extension.
Your payments extension configures the following fields:
Property name | Description |
---|---|
payment_session_url Required |
The URL that receives payment and order details from the checkout. |
refund_session_url Required |
The URL that refund session requests are sent to. |
capture_session_url Optional |
The URL that capture session requests are sent to. This is only used if your payments app supports merchant manual capture. |
void_session_url Optional |
The URL that void session requests are sent to. This is only used if your payments app supports merchant manual capture or void payments. |
confirm_session_url Optional |
The URL that confirm session requests are sent to. This URL is required if your payments app supports 3-D Secure authentication. |
supported_countries Required |
The countries where your payments app is available. Refer to the list of ISO 3166 (alpha-2) country codes where your app is available for installation by merchants. |
supported_payment_methods Required |
The payment methods (for example, Visa) that are available with your payments app. Learn more. |
supports_installments Required |
Enables installments |
supports_deferred_payments Required |
Enables deferred payments |
merchant_label Optional |
The name for your payment provider extension. This name is displayed to merchants in the Shopify admin when they search for payment methods to add to their store. Limited to 50 characters. |
buyer_label Optional |
The name of the method. Your checkout name can be the same as your merchant admin name or it can be customized for customers. This name is displayed with the payment methods that you support in the customer checkout. After a checkout name has been set, translations should be provided for localization. |
test_mode_available Optional |
Enables merchants using your payments app to test their setup by simulating transactions. To test your app on a development store, your payment provider in the Shopify admin must be set to test mode. |
api_version Optional |
The Payments Apps GraphQL API version used by the payment provider app to receive requests from Shopify. You must use the same API version for sending GraphQL requests. You can't use the unstable version of the API in production. API versions are updated in accordance with Shopify's general API versioning timelines. |
multiple_capture Optional, Closed Beta |
Enables merchants using your payment provider app to partially capture an authorized payment multiple times up to the full authorization amount. This is used only if your payments app supports merchant manual capture. |
balance_url Required |
The URL that balance requests are sent to. |
ui_extension_handle Required |
The UI extension that will be used to render your payments app in checkout. This value can only be a UI extension linked to this specific payments app. |
checkout_payment_method_fields Required |
The fields your payments app will accept from buyers in checkout (for example, installment details, payment plan). Each field is composed of a key name, as well as the data type, that restricts the input the buyer can provider. |
The UI extension generated in Create a Checkout UI extension will determine what fields, validation, and form submission behavior is presented to buyers during checkout.
UI Extension
Anchor link to section titled "UI Extension"This is where you would identify the checkout extension you built prior to creating your payment extension to tie them into one another.
Property name | Description |
---|---|
ui_extension_handle Required |
The UI extension that will be used to render your payments app in checkout. This value can only be a UI extension linked to this specific payments app. |
UI Extension Field Definitions
Anchor link to section titled "UI Extension Field Definitions"The fields you are looking to accept from your UI extensions so the payment method can validate the correct data is sent from the front end.
Property name | Description |
---|---|
checkout_payment_method_fields Required |
The fields your payments app will accept from buyers in checkout (for example, installment details, payment plan). Each field is composed of a key name, as well as the data type, that restricts the input the buyer can provider. |
The above field definitions would be defined for something that looks like this:
Step 5: Implement the Checkout UI extension
Anchor link to section titled "Step 5: Implement the Checkout UI extension"Your UI extension must extension target the purchase.checkout.gift-card.render
extension point. This will ensure your UI renders in the correct location for gift card payments and has access to the applyRedeemableChange
API method to apply a gift card to a checkout.
applyRedeemableChange
is a new API method which can be pulled from the useApplyRedeemableChange
hook on @shopify/ui-extensions-react/checkout.
applyRedeemableChange
Anchor link to section titled "applyRedeemableChange"This method applies a redeemable (i.e. gift card) to the checkout your extension is rendered on. This method triggers a Fetch Balance request explained later.
The attributes provided to this method should mirror the definitions in the UI Extension Field Definitions configuration on your payments app extension. If the attributes provided don’t match your field definitions, the call will fail and an error will be returned.
Example applyRedeemableChange
payload:
Example applyRedeemableChange
usage:
When applyRedeemableChange successfully completes, the following will be returned:
A number of errors may rise when applyRedeemableChange
is run and fails. The output would look like:
message
is human-readable, and can be any of:
- Could not apply redeemable
- Access denied: the extension does not have the required approval scopes
- Invalid RedeemableChange type
- Could not apply redeemable change: the buyer journey is completed
These messages are for debugging and should not be displayed to the buyer. Shopify owns displaying errors to buyers within checkout.
Refer to the Sample Checkout UI extension for an example implementation of what your gift card form will look like.
Things to consider
Anchor link to section titled "Things to consider"While implementing the UI extension you may want to consider the following:
- Localization - The labels and visible text displayed to the buyer should be localized. We provide the useTranslate hook through the StandardAPI for this purpose.
- Field validation - Before making the
applyRedeemableChange
request, it is advisable to validate the gift card input fields. To present field validation messages, you can utilize the error property provided by the TextField component. - Loading, Error, and Success states - When the buyer submits a gift card, your UI extension needs to handle loading, error, and success states. To accomplish this:
- Loading state: Display a loading spinner in the “Apply” button while the request is pending. To achieve this, you can use the Spinner component.
- Success state: Reset the form fields to their initial state after successfully applying the gift card to the checkout.
- Error state: Do not reset the form fields in case of an error. Instead, you may want to indicate which fields need to be corrected by utilizing field validation errors.
- Responsive UI - Use StyleHelper to make your UI extension responsive to different viewport sizes, focus states, and hover states.
Implement the payments app
Anchor link to section titled "Implement the payments app"Payments apps for gift cards are implemented very similarly to the existing offsite payments apps. The key difference is that, for gift cards, payments apps have an operation that occurs prior to a checkout completing - fetching the balance of a gift card.
Step 1: Fetch Balance
Anchor link to section titled "Step 1: Fetch Balance"The first step in a gift card payment is to retrieve the balance, so that it can be applied to a checkout. In order to do so, we require that you set up a Balance URL in the payments app extension. Shopify will make a request to that URL to retrieve the balance of a gift card during checkout.
Example request payload:
Request body
Anchor link to section titled "Request body"Attribute | Description | Type |
---|---|---|
id |
Globally unique identifier for the fetch balance attempt. Used as the idempotency key. Ensures that repeated requests with the same ID are treated the same, preventing duplicate fetch balance sessions. | String |
currency |
Three-letter ISO 4217 currency code. For example USD or CAD . |
String |
test |
Indicates whether the payment is in test or live mode. | Boolean |
merchant_locale |
IETF BCP 47 language tag representing the language used by the merchant. For example, en-US or fr-FR .
|
String |
payment_method |
Indicates the type and data relevant for the chosen payment method. Refer to payment_method hash for more information. | Hash |
payment_method
hash
Anchor link to section titled "payment_method hash"Attribute | Description | Type |
---|---|---|
type |
Indicates the type of payment method. Currently only "redeemable" is supported. |
String |
data |
Contains data relevant for the chosen payment method. Refer to payment_method.data hash for more information. | Hash |
payment_method.data
hash
Anchor link to section titled "payment_method.data hash"Attribute | Description | Type |
---|---|---|
attributes |
Contains the gift card details associated with the buyer. For example, card_number and pin . These fields are defined by the UI Extension Field Definitions configuration in your payments extension. |
String |
If the balance can be successfully fetched, send a HTTP 2xx response to the above request with a JSON body in the following format, including the balance:
The provided value for currency
can be any ISO 4217 currency code (i.e. USD, CAD).
In the event a balance fetch fails, there are a number of predefined codes you can respond with to surface an error to buyers.
Error Code | Description |
---|---|
REDEEMABLE_INVALID | The redeemable’s parameters are invalid. This is a generic error response. |
REDEEMABLE_INSUFFICIENT_BALANCE | The redeemable has insufficient balance. |
REDEEMABLE_EXPIRED | The redeemable has expired. |
REDEEMABLE_DISABLED | The redeemable was disabled. |
Example failure response (HTTP 2xx):
Fetch balance sequence diagram
Anchor link to section titled "Fetch balance sequence diagram"- The buyer enters their gift card details into the UI Extension.
- The UI extension, with the gift card details, calls
applyRedeemableChange
, available through @shopify/ui-extensions-react/checkout. - Shopify will call the payments app’s endpoint located at their configured Balance URL, with a request to fetch the balance of the provided gift card.
- The payments app returns the balance for the gift card.
- Shopify applies the gift card to the buyer’s checkout.
- The buyer is shown that the gift card has been applied to their checkout.
Step 2: Process Payment
Anchor link to section titled "Step 2: Process Payment"Payments with payments apps are processed asynchronously. When the buyer completes their checkout, a request will be sent from Shopify to the Payment session URL defined in Configure your payments app extension, with the checkout and payment details. The Payments app should respond with HTTP 2xx to indicate that the payment session was started, and should begin processing the gift card payment at this point.
Example request body:
Details on each attribute can be found here.
The payment method data object in the payment session request body is defined by the aforementioned UI Extension Field Definitions configuration in your app extension, just like for Fetch Balance.
If the request fails, then it's retried several times. If the request still fails, then the customer needs to retry their payment through Shopify checkout.
If there's an error on the payments app's side, then don't respond with an HTTP 2xx. Use an appropriate error status code instead.
Once the payments app has responded to the initial start payment session request, it should begin processing the payment. Since this is an asynchronous process, the payments app will be performing the next step independently, through the paymentSessionResolve mutation on the Payments Apps GraphQL API. This mutation will resolve the payment session, indicating that the payment was successful.
Example GraphQL mutation:
With this input:
Example JSON response:
After this, the payment will be marked as resolved in Shopify.
If a payment was unsuccessful for any reason, the payments app must use the paymentSessionReject mutation.
Example GraphQL mutation:
With this input:
Example JSON response:
There are some defined errors that you can reject a paymentSession with.
Error Code | Description |
---|---|
PROCESSING_ERROR | There was an error processing the payment. |
Step 3: Refunds
Anchor link to section titled "Step 3: Refunds"Refunds operate the same as they do with regular payments. Documentation can be found here.
Optional: Authorizations, Captures, and Voids
Anchor link to section titled "Optional: Authorizations, Captures, and Voids"Authorizations, captures, and voids allow merchants to use your payment app to initiate separate transactions to authorization and capture payments. These will operate the same as they do with regular payment apps. More context about authorizations can be found here.
Merchants control whether or not they use "sale or "authorization" payment transactions by changing their Payment capture method payment setting to "Manual" or "Automatically when order is fulfilled".
For details on how to implement and respond to capture and void session requests see:
Diagram | Documentation | |
---|---|---|
Captures | Capture overview | Explore capture sessions |
Voids | Void overview | Explore void sessions |
Sample Checkout UI Extension
Anchor link to section titled "Sample Checkout UI Extension"Use the following example for implementing your gift card form:
Tutorial Complete
Anchor link to section titled "Tutorial Complete"Congratulations! You set up a redeemable payments extension.