> NOTE: This API is **only available to select merchants and partners** using 3rd party checkout solutions. For more information, contact [our enterprise sales team](https://www.shopify.com/solutions/shop-pay/enterprise#contact-sales).
## Overview
The Shop Component JS API enables your existing ecommerce site to use Shop Pay for checkout. Customers who select a Pay with Shop button or are recognized by email are shown all relevant cart information and can complete the transaction in an experience consistent with other usages of Shop Pay using a popup on your site.
### Glossary
| **Term** | **Definition** |
|---|---|
| Shop Pay login | Logging in to a Shop Pay account. This occurs directly between a customer and Shopify. |
| Payment request | A payment request includes line items, applied discounts, tax calculations and available shipping methods. |
| Authentication modal | When a Shop Pay user's email is recognized, the customer will see an interface to enter a One Time Password (OTP) for authentication. |
| Shop Pay popup | Most of the interactions in Shop Pay Checkout happen within the context of a Shopify-hosted popup window. |
### Technical requirements
* A Shopify account with Shopify Payments enabled
* The public domain(s) for the site you will be integrating Shop Component into
* A non-Shopify-hosted ecommerce environment to implement against (frontend + backend)
* The content security policy on the frontend must be configured to allow `cdn.shopifycloud.com`, `cdn.shopify.com`, `shop.app`, `pay.shopify.com`, `*.shopifysvc.com`, `*.stripe.com`
* The backend needs to be able to functionally access all applicable resources required to assess and update the state of the payment request, including cart details, tax calculations, shipping methods / pricing, local pickup locations, discounts, inventory availability, etc.
* An understanding of the work necessary to integrate with the Order Management System and other backend systems to perform post-order actions in Shopify such as captures, refunds, and updating fulfillment information.
### Core Concepts
#### Your system is the main source of truth
This API extends your existing systems, so it treats those systems as canonical for everything that they already handle. This includes:
* Cart contents
* Shipping methods
* Pickup locations
* Tax calculation
* Discounts
* Inventory reservations
Shopify is the source of truth for the payment transaction and for Shop Pay related fields, including vaulted customer addresses and payment methods.
Consequently, while this API receives detailed information about the cart in the form of a payment request, any changes to the payment request related to your system's canonical topics must be validated. Whenever the payment request is returned to Shopify, it's used as a replacement for prior data received.
#### Shopify's order ID
Upon payment completion, the order ID is returned from Shopify via a webhook for use in post-order actions such as capturing payments, issuing refunds, and adding order tracking information.
#### Source identifier
Your system is responsible for providing a source identifier that uniquely identifies the order, and is often either an existing cart or order identifier from your system. This value is persisted onto the Shopify order record.
#### Authentication
You will need to create a [custom app](/docs/apps/build/authentication-authorization/access-tokens/generate-app-access-tokens-admin) in Shopify, granting a shared key and Shopify API access tokens.
#### Shop Pay popup interactions
Shop Pay customers will authenticate with a Shop Pay login, either through an authentication modal or directly within the Shop Pay popup.
In order for Shopify to receive your system's canonical information during the checkout process, Shopify will dispatch events to your frontend integration when there are relevant customer actions in the Shop Pay popup. Following this, your system will then determine if there are any subsequent updates required to be made to the payment request. Based on its new state, calculate and rebuild an updated payment request to provide in the required response to the event.
Once accepted by a customer through the action of clicking the _Pay now_ button, your backend should submit the [final payment request mutation](/docs/api/storefront/2024-07/mutations/shopPayPaymentRequestSessionSubmit), including the `paymentMethod` token provided by Shopify, resulting in processing the payment and order creation.
While the Shop Pay popup is open, an overlay will darken the background, however the cart on your shop may remain visible. It's important that a customer does not see a different total in the cart because it hasn't updated based on selected shipping methods or discounts applied in Shop Pay. To handle this, we recommend updating any cart totals while the user interacts with the Shop Pay Checkout so that values match. A potential fallback is displaying the totals in a pending state through microcopy like `Calculating...` or through skeletons, spinners, or other pending UI elements.
#### Order creation
A payment request must first be validated in your system including verifying that the payment request hasn't been modified unexpectedly, confirming inventory reservation, discount and pricing validation before submitting the final Shop Pay payment request, which will then create the order in Shopify.
Although rare, there can be a delay before an order becomes available via the Shopify API. It's important to ensure that synchronous order creation is not required for
functionality of your checkout. Instead, webhooks can be relied upon for order creation confirmation.
## Sequence Diagram
This diagram reflects a "happy path" checkout. For simplicity, it bypasses the Shop Pay login flow, assuming a customer is already logged into Shop Pay.
## JavaScript SDK for buttons and email recognition
Shopify provides **Shop Pay button** and **Shop Pay Login** Web Components that you can add to your store.
Use the following code to load the script into your webpage from the CDN and embed the components.
```javascript
// This script must be placed in the
of your site on any pages where Shop Pay components exist.
// In most cases this will be in your checkout, however it may also be included on product and/or cart pages where necessary.
```
### `configure` parameters
| **Parameter** | **Type** | **Description** |
|---|---|---|
| `shopId` | Number | A required parameter. This is the ID for the shop. The `shopId` (integer) can be retrieved from the `shop` object in the [Admin API](/docs/api/admin-graphql/latest/queries/shop). |
| `clientId` | String | A required parameter. This is the unique identifier for the client. The `clientId` is provided by Shopify. |
| `debug` | Boolean | An optional parameter. When set to `true`, it enables debug mode, which will console log additional information that can be useful for development and troubleshooting. This should be omitted in production environments. |
| `onAnalyticsEvent` | Function | An optional parameter. This is a callback function that will be invoked with specific `Event` objects. This can be useful for monitoring user interactions and gathering data. See below for supported events. |
| `locale` | ShopPayLocale | An optional parameter. Specifies the desired locale for the checkout experience. Expects a valid ISO language code, optionally followed by an ISO country code. Defaults to English (`en`). For a list of supported locales, see the [Supported Locales List](#supported-locales-list) section.|
#### Analytics
The following events are currently supported:
* `loginpromptdisplayed`: This event is triggered when the Shop Pay login modal prompt is displayed.
* `windowopened`: This event is triggered when the Shop Pay popup checkout window is opened.
* `windowclosed`: This event is triggered when the Shop Pay popup checkout window is closed.
Here's an example of how you might handle these events in your `onAnalyticsEvent` callback:
```javascript
```
### Shop Pay Login
#### `createLogin` parameters
| **Parameter** | **Type** | **Description** |
|---|---|---|
| `emailInputId` | String | A required parameter. The unique identifier of the email input element to listen to. This is also used to anchor the login modal to an element. |
### Shop Pay button
#### `createButton` parameters
| **Parameter** | **Type** | **Description** |
|---|---|---|
| `buyWith` | Boolean | An optional parameter. If true, displays the "Buy with" variant of the button. Defaults to `false`. |
#### CSS Properties
| **Name** | **Description** | **Constraints** |
| --- | --- | --- |
| `--shop-pay-button-width` | The width of the button. | Default: `262px`
Minimum: `120px`
Minimum (`buy-with`): `193px`|
| `--shop-pay-button-height` | The height of the button. | Default: `42px`
Minimum: `40px` |
| `--shop-pay-button-border-radius` | The border radius of the button. | Default: `4px` |
The following example styles the button with the default height of 42 pixels, a width of 200 pixels, and a border radius of 0 pixels:
```javascript
```
> Note:
Upon invoking the `.render` method, the button is optimistically rendered while an HTTP request is dispatched to Shopify to check the availability of Shop Pay in the configured shop. If the Shopify Payments setup is incomplete or Shop Pay is deactivated in the payment settings, the button element is removed from the DOM.
#### Enabling and disabling the Shop Pay button
If you need to disable and re-enable the Shop Pay button for specific user interactions or other conditions in your application, you can use the following methods.
```javascript
// Disable the Shop Pay button
window.ShopPay.PaymentRequest.Buttons.disable();
// Re-enable the Shop Pay button
window.ShopPay.PaymentRequest.Buttons.enable();
```
Example: Disable the Shop Pay button until a valid variant is selected
```javascript
// Disable the payment request button to prevent a customer from opening Shop Pay before a variant is selected
window.ShopPay.PaymentRequest.Buttons.disable();
const addProductToCartButton = document.getElementById('addProductToCartButton');
addProductToCartButton.addEventListener('click', function() {
// Once the selected valid variant has been successfully processed, re-enable the button
window.ShopPay.PaymentRequest.Buttons.enable();
});
```
## Example code
The example code below provides guidance on how to use Shop Component.
### Configure the API
Use the `.myshopify.com` hostname from your onboarding email to configure the API.
```javascript
window.ShopPay.PaymentRequest.configure({
shopId: 1,
clientId: "[REPLACE-ME.myshopify.com]",
})
```
### Create a session
Create a session to make a payment request. `shop_id` (`integer`) can be retrieved from the `shop` object in the [Admin API](/docs/api/admin-graphql/latest/queries/shop).
[PaymentRequest fields are defined below.](#shoppaypaymentrequest)
```javascript
const initialPaymentRequest = window.ShopPay.PaymentRequest.build({
lineItems: [
{
label: "T-Shirt",
originalItemPrice: {
amount: 10.00,
currencyCode: "USD"
},
itemDiscounts: [
{
label: "10% off",
amount: {
amount: 1.00,
currencyCode: "USD"
}
}
],
finalItemPrice: {
amount: 9.00,
currencyCode: "USD"
},
quantity: 2,
sku: "t-shirt",
requiresShipping: true,
originalLinePrice: {
amount: 20.00,
currencyCode: "USD"
},
lineDiscounts: [
{
label: "10% off",
amount: {
amount: 2.00,
currencyCode: "USD"
}
}
],
finalLinePrice: {
amount: 18.00,
currencyCode: "USD"
},
}
],
discountCodes: [],
deliveryMethods: [],
subtotal: {
amount: 18.00,
currencyCode: "USD"
},
totalTax: {
amount: 1.25,
currencyCode: "USD"
},
total: {
amount: 19.25,
currencyCode: "USD"
},
presentmentCurrency: "USD",
locale: 'en',
});
const session = window.ShopPay.PaymentRequest.createSession({
paymentRequest: initialPaymentRequest
});
```
### Attach event listeners
Use [`ShopPayPaymentRequestSessionCreate`](#example-shoppaypaymentrequestsessioncreate) on your server to create a session.
```javascript
session.addEventListener("sessionrequested", (ev) => {
// Shop Pay Payment Request Session on your server
const response = fetch('/replace_with_your_endpoint', {
method: 'POST',
body: JSON.stringify({
payment_request: initialPaymentRequest
}),
headers: {
'Content-Type': 'application/json',
},
}).then(response => response.json()).then(data => {
const {token, checkoutUrl, sourceIdentifier} = data;
// optionally update the payment request if it has changed since it was created
const updatedPaymentRequest = window.ShopPay.PaymentRequest.build({YOUR_UPDATED_PAYMENT_REQUEST});
session.completeSessionRequest({token, checkoutUrl, sourceIdentifier, updatedPaymentRequest});
});
});
```
Listen to events that may change calculations such as when a delivery method
type, shipping address, delivery method, pickup location, pickup location
filter, or discount code changes. Recalculate the payment request and update the
session.
```javascript
session.addEventListener("deliverymethodtypechanged", async (ev) => {
const currentPaymentRequest = session.paymentRequest;
const deliveryMethodType = ev.deliveryMethodType;
let pickupLocations = [];
if (deliveryMethodType === 'PICKUP') {
pickupLocations = await fetchPickupLocations();
}
// Update the payment request based on the delivery method type change
const updatedPaymentRequest = window.ShopPay.PaymentRequest.build({
...currentPaymentRequest,
pickupLocations,
});
session.completeDeliveryMethodTypeChange({ updatedPaymentRequest: updatedPaymentRequest });
});
```
```javascript
session.addEventListener("shippingaddresschanged", async (ev) => {
const currentPaymentRequest = session.paymentRequest;
const selectedAddress = ev.shippingAddress;
// Update the payment request based on the shipping address change
const updatedPaymentRequest = window.ShopPay.PaymentRequest.build({
...currentPaymentRequest,
deliveryMethods: [
{
label: "Standard",
amount: {
amount: 10.00,
currencyCode: "USD"
},
code: "STANDARD",
minDeliveryDate: '2024-01-01',
maxDeliveryDate: '2027-01-01',
},
{
label: "Express",
amount: {
amount: 20.00,
currencyCode: "USD"
},
code: "EXPRESS",
minDeliveryDate: '2024-01-01',
maxDeliveryDate: '2026-01-01',
}
]
});
session.completeShippingAddressChange({ updatedPaymentRequest: updatedPaymentRequest });
});
```
```javascript
session.addEventListener("deliverymethodchanged", async (ev) => {
const currentPaymentRequest = session.paymentRequest;
const selectedDeliveryMethod = ev.deliveryMethod;
let updatedRequestValues;
if (selectedDeliveryMethod) {
updatedRequestValues = {shippingLines: [{
label: selectedDeliveryMethod.label,
amount: selectedDeliveryMethod.amount,
code: selectedDeliveryMethod.code
}],
totalShippingPrice: {
finalTotal: {
amount: selectedDeliveryMethod.amount.amount,
currencyCode: "USD",
},
},
total: {
amount: 20 + selectedDeliveryMethod.amount.amount,
currencyCode: "USD"
}}
} else {
updatedRequestValues= {total: {
amount: 20,
currencyCode: "USD"
}}
}
// Update the payment request based on the delivery method change
// and update the totals accordingly
const updatedPaymentRequest = window.ShopPay.PaymentRequest.build({
...currentPaymentRequest,
...updatedRequestValues,
});
session.completeDeliveryMethodChange({ updatedPaymentRequest: updatedPaymentRequest });
});
```
```javascript
session.addEventListener("pickuplocationchanged", async (ev) => {
const currentPaymentRequest = session.paymentRequest;
const pickupLocation = ev.pickupLocation;
// Update the payment request based on the pickup location change
// and update the totals accordingly
const updatedPaymentRequest = window.ShopPay.PaymentRequest.build({
...currentPaymentRequest,
totalShippingPrice: {
finalTotal: {
amount: pickupLocation.amount.amount,
currencyCode: "USD",
},
},
total: {
amount: 20 + pickupLocation.amount,
currencyCode: "USD"
},
});
session.completePickupLocationChange({ updatedPaymentRequest: updatedPaymentRequest });
});
```
```javascript
session.addEventListener("pickuplocationfilterchanged", async (ev) => {
const currentPaymentRequest = session.paymentRequest;
const buyerLocation = ev.buyerLocation;
// Update the payment request based on the pickup location filter change
// by filtering the available pickup locations based on a customer's location
const updatedPaymentRequest = window.ShopPay.PaymentRequest.build({
...currentPaymentRequest,
pickupLocations: [{
label: "620 King Street West",
code: "PICK_UP-KING-STREET-WEST",
detail: "620 King Street West, Toronto, ON",
amount: {
amount: 10.00,
currencyCode: "USD"
},
readyExpectationLabel: "Ready in 1 hour",
proximityLabel: "Less than 1 km away",
}]
});
session.completePickupLocationFilterChange({ updatedPaymentRequest: updatedPaymentRequest });
});
```
```javascript
session.addEventListener("discountcodechanged", async (ev) => {
const currentPaymentRequest = session.paymentRequest;
const selectedDiscountCodes = ev.discountCodes; // Array of discount codes ["example-code-1"]
// Update the payment request based on the discount code change
// Let's assume the discount code is valid and the discount is 15% off
const updatedPaymentRequest = window.ShopPay.PaymentRequest.build({
...currentPaymentRequest,
discountCodes: selectedDiscountCodes,
lineItems: [
{
label: "T-Shirt",
finalItemPrice: {
amount: 10.00,
currencyCode: "USD"
},
quantity: 2,
sku: "t-shirt",
requiresShipping: true,
finalLinePrice: {
amount: 20.00,
currencyCode: "USD"
},
}
],
subtotal: {
amount: 20.00,
currencyCode: "USD"
},
discounts: [
{
label: "example-code-1",
amount: {
amount: 3.00 // Discounts must be passed to Shopify as a positive value
currencyCode: "USD"
}
}
],
totalTax: {
amount: 1.06,
currencyCode: "USD"
},
total: {
amount: 18.06,
currencyCode: "USD"
}
});
session.completeDiscountCodeChange({ updatedPaymentRequest: updatedPaymentRequest });
});
```
Confirm the payment once the user clicks the _Pay now_ button in the Shop Pay popup.
The server confirmation must invoke the `ShopPayPaymentRequestSessionSubmit` mutation to confirm that the payment is to be processed.
Use [`ShopPayPaymentRequestSessionSubmit`](#example-shoppaypaymentrequestsessionsubmit) on your server to submit the session.
```javascript
session.addEventListener("paymentconfirmationrequested", async (_ev) => {
// Before submitting the payment request for processing, a final check should be done on your server
// to make sure the payment request (total price, inventory available, etc.) is still valid.
const response = fetch('/replace_with_your_endpoint', {
method: 'POST',
body: JSON.stringify({
token: session.token,
payment_request: session.paymentRequest
}),
headers: {
'Content-Type': 'application/json',
},
}).then(response => response.json()).then(data => {
if (data.errors) {
// Handle errors here.
// For example: if an item is no longer in stock, you can send a new paymentRequest without that lineItem by building a new payment request and including it in completePaymentConfirmationRequest along with the errors.
session.completePaymentConfirmationRequest({
errors: [
{
"type": "generalError",
"message": "Something went wrong. Please try again."
}
// Optionally build an updated paymentRequest and include it here
]
})
} else {
// confirm the payment request is processing
session.completePaymentConfirmationRequest();
}
});
});
```
This event is dispatched when the payment is complete. Close the Shop Pay popup and redirect the user to the order confirmation page.
```javascript
session.addEventListener("paymentcomplete", async (ev) => {
console.log(ev.processingStatus.status);
session.close(); // close the Shop Pay popup
window.location.href = "/thank-you";
});
```
This event is dispatched when a payment attempt fails. The event contains information about why the payment failed.
```javascript
session.addEventListener("paymentattemptfailed", async (ev) => {
const { reason, errorCode } = ev.error;
console.log(`Payment attempt failed: ${reason}`);
console.log(`Error code: ${errorCode}`);
});
```
This event is dispatched when the checkout window is closed.
```javascript
session.addEventListener("windowclosed", async () => {
// handle window closed event
});
```
> Warning:
> Only call the corresponding complete call once for each event.
## API Reference: Frontend
### ShopPayPaymentRequestSession
These events are what Shopify will emit as the user interacts with Shop Pay which you must listen for and respond accordingly. [See examples above](#attach-event-listeners).
```javascript
interface ShopPayPaymentRequestSession {
// Requires a server call
sessionrequested: EventHandler;
completeSessionRequest(sessionRequestResponse: {token, checkoutUrl, sourceIdentifier} & ShopPayPaymentRequestUpdate): void;
// Dispatched as the user changes various fields
deliverymethodtypechanged: EventHandler;
completeDeliveryMethodTypeChange(update: ShopPayPaymentRequestUpdate): void;
pickuplocationchanged: EventHandler;
completePickupLocationChange(update: ShopPayPaymentRequestUpdate);
pickuplocationfilterchanged: EventHandler;
completePickupLocationFilterChange(update: ShopPayPaymentRequestUpdate);
shippingaddresschanged: EventHandler;
completeShippingAddressChange(update: ShopPayPaymentRequestUpdate): void;
deliverymethodchanged: EventHandler;
completeDeliveryMethodChange(update: ShopPayPaymentRequestUpdate): void;
discountcodechanged: EventHandler;
completeDiscountCodeChange(update: ShopPayPaymentRequestUpdate): void;
// Dispatched once a customer clicks the Pay button in order to confirm
// the payment should be processed
paymentconfirmationrequested: EventHandler;
completePaymentConfirmationRequest(update: ShopPayPaymentRequestUpdate): void;
// Dispatched after a payment processing attempt
paymentcomplete: EventHandler;
// Dispatched when a payment attempt has failed
paymentattemptfailed: EventHandler;
// Dispatched after the checkout window is closed
windowclosed: EventHandler;
// Cancels the session
close(): void;
}
interface ShopPayPaymentRequestUpdate {
updatedPaymentRequest?: ShopPayPaymentRequest;
errors?: ShopPayUserError[];
}
```
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| `sessionrequested` | Event Handler | This event handler is triggered when a new Shop Pay session is requested. The listener must make a server-to-server call from your backend to Shop Pay's servers, and then call `completeSessionRequest()` from your frontend with the response. |
| `completeSessionRequest` | `(args: {token: string, checkoutUrl: string, sourceIdentifier: string} & ShopPayPaymentRequestUpdate) => void` | This function completes the session request. It must be invoked with the `token`, `checkoutUrl`, and `sourceIdentifier` from response of the `ShopPayPaymentRequestSessionCreate` mutation. You can optionally include an updated payment request. |
| `deliverymethodtypechanged` | Event Handler | This event handler is triggered when a customer changes their preferred delivery method. When this event is triggered, `completeDeliveryMethodTypeChange()` must be called with the updated payment request. |
| `completeDeliveryMethodTypeChange` | `(args: ShopPayPaymentRequestUpdate) => void` | This function must be called when the delivery method type changes. |
| `pickuplocationchanged` | Event Handler | This event handler is triggered when a customer changes the selected pickup location. `completePickupLocationChange()` must be called with the updated payment request. |
| `completePickupLocationChange` | `(args: ShopPayPaymentRequestUpdate) => void)` | This function must be called when the selected pickup location changes. |
| `pickuplocationfilterchanged` | Event Handler | This event handler is triggered when the pickup location filter changes. `completePickupLocationFilterChange()` must be called with an updated payment request containing a filtered set of pickup locations. |
| `completePickupLocationFilterChange` | `(args: ShopPayPaymentRequestUpdate) => void` | This function must be called when the pickup location filter changes. |
| `shippingaddresschanged` | Event Handler | This event handler is triggered when a customer changes their preferred shipping address. When this event is triggered, `completeShippingAddressChange()` must be called with the updated payment request. |
| `completeShippingAddressChange` | `(args: ShopPayPaymentRequestUpdate) => void` | This function must be called when the shipping address changes. |
| `deliverymethodchanged` | Event Handler | This event handler is triggered when a customer changes their preferred delivery method. When this event is triggered, `completeDeliveryMethodChange()` must be called with the updated payment request. |
| `completeDeliveryMethodChange` | `(args: ShopPayPaymentRequestUpdate) => void` | This function must be called when the updated payment request. |
| `discountcodechanged` | Event Handler | This event handler is triggered when the discount code changes. When this event is triggered, `completeDiscountCodeChange()` must be called with the updated payment request. |
| `completeDiscountCodeChange` | `(args: ShopPayPaymentRequestUpdate) => void` | This function updates the payment request after discount codes are changed by providing a updated payment request.|
| `paymentconfirmationrequested` | Event Handler | This event handler is triggered after a customer clicks the Pay button. The `ShopPayPaymentRequestSessionCreate` mutation must be invoked, then `completePaymentConfirmationRequest()` must be called afterwards. |
| `completePaymentConfirmationRequest` | `(args: ShopPayPaymentRequestUpdate) => void` | This function is used to confirm that Shopify must proceed with payment. If there are any errors, they must be provided in the `errors` field. If `updatedPaymentRequest` is given, `errors` must also be given. |
| `paymentcomplete` | Event Handler | This event handler is triggered after Shopify successfully processes a payment. The event payload has a `.processingStatus` field of type `ShopPayPaymentRequestReceiptCompleted`. |
| `paymentattemptfailed` | Event Handler | This event handler is triggered when a payment attempt has failed. The event payload has a `.error` field with details about why the payment attempt failed. |
| `close` | `() => void` | This function cancels the session and closes the popup. |
| `windowclosed` | EventHandler | This event handler is triggered after the checkout window is closed. |
### ShopPayPaymentRequest
A payment request is the primary means of communication between your system and Shop Pay.
> Warning:
> The frontend `ShopPayPaymentRequest`, used to display the payment request in the Shop Pay popup, is different from the backend `ShopPayPaymentRequestInput`, used in [mutations](/docs/api/storefront/latest/input-objects/ShopPayPaymentRequestInput) as part of payment processing.
```typescript
interface ShopPayPaymentRequest {
supportedDeliveryMethodTypes?: ShopPayDeliveryMethodType[];
selectedDeliveryMethodType?: ShopPayDeliveryMethodType;
pickupLocations?: ShopPayPickupLocation[];
paymentMethod?: string;
discountCodes: string[];
lineItems: ShopPayLineItem[];
shippingLines: ShopPayShippingLine[];
deliveryMethods: ShopPayDeliveryMethod[]
locale: ShopPayLocale;
presentmentCurrency: ShopPayCurrencyCode;
subtotal: ShopPayMoney;
discounts?: ShopPayDiscountLine[];
totalShippingPrice?: ShopPayTotalShippingPrice;
totalTax?: ShopPayMoney;
total: ShopPayMoney;
}
```
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| supportedDeliveryMethodTypes | `ShopPayDeliveryMethodType[] (optional)` | The supported delivery method types for this checkout. Defaults to `["SHIPPING"]`. |
| selectedDeliveryMethodType | `ShopPayDeliveryMethodType (optional)` | The selected delivery method type. |
| pickupLocations | `ShopPayPickupLocation (optional)` | The available pickup locations when the selected delivery method type is PICKUP. |
| paymentMethod | `string (optional)` | The one time use payment token, included only in the `paymentconfirmationrequested` event. |
| discountCodes | `ShopPayDiscountCode[]` | All applied discount codes, displayed under the discount code field as tags. |
| lineItems | `ShopPayLineItem[]` | The line items to display. |
| shippingLines | `ShopPayShippingLine[]` | The shipping line items to display. |
| deliveryMethods | `ShopPayDeliveryMethod[]` | The available delivery methods. |
| locale | `ShopPayLocale` | A locale iso code such as 'en' used to inform the display of instructions and amounts. |
| presentmentCurrency | `ShopPayCurrencyCode` | The three-letter currency code that represents the world currency for the transaction. These include standard ISO 4217 codes, legacy codes, and non-standard codes. |
| subtotal | `ShopPayMoney` | The subtotal of the line items, calculated as the sum of the `finalLinePrice` from all lines. |
| discounts | `ShopPayDiscountLine[] (optional)` | All discounts applied to the subtotal. These must be positive values. |
| totalShippingPrice | `ShopPayTotalShippingPrice (optional)` | The total shipping price after all applicable discounts, not including tax. |
| totalTax | `ShopPayMoney (optional)` | The total tax from all line items and shipping charges. |
| total | `ShopPayMoney` | The grand total includes all applicable discounts, shipping charges, and taxes. The customer will be charged this amount. |
### ShopPayDeliveryMethodType
One of the following delivery method types:
* `PICKUP` - The customer will buy online and pickup the order.
* `SHIPPING` - The customer's order will be shipped.
### ShopPayLineItem
Represents line items in a payment request including cart line items, order-level line items such as discounts and taxes, and the grand total.
```typescript
interface ShopPayLineItem {
label: string;
quantity: number;
sku?: string;
requiresShipping?: boolean;
image?: ShopPayLineItemImage;
originalItemPrice?: ShopPayMoney;
itemDiscounts?: ShopPayDiscountLine[];
finalItemPrice: ShopPayMoney;
originalLinePrice?: ShopPayMoney;
lineDiscounts?: ShopPayDiscountLine[];
finalLinePrice: ShopPayMoney;
}
```
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| label | `string` | The label for the line item. |
| quantity | `number` | The quantity of the line item. |
| sku | `string (optional)` | The merchandise SKU if needed for inventory tracking and reporting. |
| requiresShipping | `boolean (optional)` | Whether the line item requires shipping. Defaults to `true`. |
| image | `ShopPayLineItemImage (optional)` | The image associated with the line item. |
| originalItemPrice | `ShopPayMoney (optional)` | The original price of the item. Used to show price before any applicable discounts are applied, and must be included for all non-free items. |
| itemDiscounts | `ShopPayDiscountLine[] (optional)` | All discounts applied to the item. These must be positive values. |
| finalItemPrice | `ShopPayMoney` | The final price of the item after all applicable discounts. |
| originalLinePrice | `ShopPayMoney (optional)` | The original price of the line item. Used to show price before any applicable discounts are applied, and must be included for all non-free lineItems. |
| lineDiscounts | `ShopPayDiscountLine[] (optional)` | All discounts applied to the line item. |
| finalLinePrice | `ShopPayMoney` | The final price of the line item based on quantity * item price including all applicable discounts. |
### ShopPayLineItemImage
The image associated with the line item.
```typescript
interface ShopPayLineItemImage {
url: string;
alt?: string;
}
```
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| url | `string` | The URL of the image. Recommended: 128x128px, 1:1 ratio image. |
| alt | `string (optional)` | The alt text associated with the image. |
### ShopPayTotalShippingPrice
Represents the total shipping price in a payment request.
```typescript
interface ShopPayTotalShippingPrice {
discounts?: ShopPayDiscountLine[];
originalTotal?: ShopPayMoney;
finalTotal: ShopPayMoney;
}
```
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| discounts | `ShopPayDiscountLine[] (optional)` | All discounts applied to the shipping price. These must be positive values. |
| originalTotal | `ShopPayMoney (optional)` | The original total shipping price. Used to show shipping price before any applicable discounts are applied, and must be included for all non-free shipping methods. |
| finalTotal | `ShopPayMoney` | The final total shipping price. Price after all applicable discounts. |
### ShopPayDiscountLine
Represents discount lines in a payment request.
```typescript
interface ShopPayDiscountLine {
label: string;
amount: ShopPayMoney;
}
```
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| label | `string` | The label for the discount line. |
| amount | `ShopPayMoney` | The amount of the discount as a positive value. |
### ShopPayShippingLine
Represents shipping line items in a payment request.
```typescript
interface ShopPayShippingLine {
label: string;
amount: ShopPayMoney;
code: string;
}
```
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| label | `string` | The label for the shipping line item. |
| amount | `ShopPayMoney` | The amount of the shipping line item. |
| code | `string` | The service code of the shipping rate. Corresponds to `ShopPayDeliveryMethod#code`. |
### ShopPayMoney
Represents an amount and the associated currency.
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| amount | `number` | |
| currencyCode | `ShopPayCurrencyCode` | |
### ShopPayContactField
Represents a shipping contact.
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| countryCode | `string` | The country ISO-3166 code of the contact. |
| postalCode | `string (optional)` | The postal code of the contact. |
| provinceCode | `string (optional)` | The province (or state) ISO-3166 code of the contact. |
| city | `string` | The city of the contact. |
| firstName | `string (optional)` | The first name of the contact. |
| lastName | `string` | The last name of the contact. |
| address1 | `string` | The address of the contact. |
| address2 | `string (optional)` | The address2 of the contact. |
| phone | `string (optional)` | The phone number of the contact. |
| email | `string (optional)` | The email address of the contact. |
| companyName | `string (optional)` | The company name of the contact. |
### ShopPayPickupLocation
Represents an available order pickup location. Pickup locations are displayed to a customer if they select `PICKUP` as the delivery method type.
```typescript
interface ShopPayPickupLocation {
label: string;
detail: string;
code: string;
amount: ShopPayMoney;
readyExpectationLabel?: string;
proximityLabel?: string;
}
```
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| label | `string` | The label for the pickup location. |
| detail | `string` | The detail describing the pickup location. |
| code | `string` | The code for the pickup location used to uniquely identify it. |
| amount | `ShopPayMoney` | The amount of the pickup. |
| readyExpectationLabel | `string (optional)` | The description of when the order will be ready for pickup. |
| proximityLabel | `string (optional)` | The description for the proximity of the pickup location relative to the customer. |
### ShopPayDeliveryMethod
```typescript
interface ShopPayDeliveryMethod {
code: string;
label: string;
detail?: string;
amount: ShopPayMoney;
minDeliveryDate?: ISO8601Date;
maxDeliveryDate?: ISO8601Date;
deliveryExpectationLabel?: string;
}
```
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| code | `string` | The service code of the shipping rate. |
| label | `string` | The service name of the shipping rate. |
| detail | `string (optional)` | The description of the shipping rate. |
| amount | `ShopPayMoney` | The total price amount of the shipping rate. |
| minDeliveryDate | `ISO8601Date (optional)` | The minimum delivery date. ISO 8601-encoded date string. Required unless deliveryExpectationLabel provided. |
| maxDeliveryDate | `ISO8601Date (optional)` | The maximum delivery date. ISO 8601-encoded date string. Required unless deliveryExpectationLabel provided. |
| deliveryExpectationLabel | `String (optional)` | If provided, will be displayed as further detail for expected delivery, replacing the calculated delivery estimate. |
### ShopPayPaymentRequestUpdate
Represents an updated state of the checkout. At least one of an updated
payment request and an array of errors should be provided.
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| updatedPaymentRequest | `ShopPayPaymentRequest (optional)` | The updated payment request. If not provided, the current payment request will continue to be used. |
| errors | `ShopPayUserError[] (optional)` | An array of errors. |
### PickupLocationChangedEvent
Dispatched when a customer changes their pickup location.
```typescript
interface PickupLocationChangedEvent extends Event {
pickupLocation: ShopPayPickupLocation;
}
```
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| pickupLocation | `ShopPayPickupLocation` | The customer's pick up location. |
### PickupLocationFilterChangedEvent
Dispatched when a customer changes their pickup location filter.
```typescript
interface PickupLocationFilterChangedEvent extends Event {
buyerLocation: ShopPayBuyerLocation;
}
```
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| buyerLocation | `ShopPayBuyerLocation` | The customer's location used to filter pickup locations. |
### DeliveryMethodTypeChangedEvent
Dispatched when a customer changes their delivery method type.
```typescript
interface DeliveryMethodTypeChangedEvent extends Event {
deliveryMethodType: ShopPayDeliveryMethodType;
}
```
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| deliveryMethodType | `ShopPayDeliveryMethodType` | The delivery method type selected by the user. |
### ShopPayBuyerLocation
Represents a customer's location. Use this to set the available pickup locations.
```typescript
interface ShopPayBuyerLocation {
address1?: string;
address2?: string;
city?: string;
provinceCode?: string;
countryCode?: string;
postalCode?: string;
coordinates?: {
latitude: number;
longitude: number;
};
}
```
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| address1 | `string` | The address of the contact. |
| address2 | `string (optional)` | The address2 of the contact. |
| city | `string` | The city of the contact. |
| provinceCode | `string (optional)` | The province (or state) ISO-3166 code of the contact. |
| countryCode | `string` | The country ISO-3166 code of the contact. |
| postalCode | `string (optional)` | The postal code of the contact. |
| coordinates.latitude | `number (optional)` | The latitude of the customer's location. |
| coordinates.longitude | `number (optional)` | The longitude of the customer's location. |
### ShopPayPaymentRequestReceiptCompleted
A successful completed receipt. Note the status will be `completed`. This event only occurs if the payment is successfully processed.
```typescript
interface ShopPayPaymentRequestReceiptCompleted {
completedAt: ISO8601Date;
billingAddress: {
countryCode: string;
postalCode?: string;
provinceCode?: string;
city?: string;
firstName?: string;
lastName?: string;
address1?: string;
phone?: string;
};
creditCardDetails?: {
brand?: string;
lastDigits?: string;
};
paymentType: "SHOP_PAY" | "SHOPIFY_INSTALLMENTS";
accountUrl?: string;
status: "completed";
}
```
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| completedAt | `ISO8601Date` | The date the receipt was completed. |
| billingAddress | `ShopPayContactField` | The billing address of the customer. |
| creditCardDetails | `{brand?: string, lastDigits?: string}` | The credit card details of the customer. |
| paymentType | `"SHOP_PAY" or "SHOPIFY_INSTALLMENTS"` | The type of payment used. |
| accountUrl | `string (optional)` | The URL to the customer's account. |
| status | `"completed"` | The status of the receipt. |
### ShopPayPaymentAttemptFailedEvent
Dispatched when a payment attempt has failed. This can happen due to various reasons such as insufficient funds, invalid payment details, or other payment processing errors.
> Note:
Buyers have the option to select a different payment method to retry their checkout after a failure. Do not call `session.close()` to allow users to retry with a new payment method without disrupting their session.
```typescript
interface ShopPayPaymentAttemptFailedEvent extends Event {
error: {
errorCode: string;
reason: string;
};
}
```
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| error | `{errorCode: string, reason: string}` | The reason why the payment attempt failed. |
### ShopPayUserError
Represents an error that is surfaced to the user during checkout.
| **Field name** | **Type** | **Description** |
| --- | --- | --- |
| type | `'generalError'` or `'discountCodeError'` or `'shippingAddressError'` | The context of the error. |
| message | `string (optional)` | The localized message shown to the user. |
* `generalError` - These errors are shown at the top of the checkout. Although we recommend setting your own message, the error text will be defaulted to "Something went wrong. Please close Shop Pay and try again".
* `discountCodeError` - These errors are shown near discount code entry. For example, to indicate that a discount code is expired. Although we recommend setting your own message, the error text will be defaulted to "Enter a valid discount code".
* `shippingAddressError` - These errors are shown near shipping address selection. For example, in order to indicate that the selected shipping address is undeliverable to. Although we recommend setting your own message, the error text will be defaulted to "Shipping not available for selected address".
> Note:
A maximum of two errors can be displayed at any given time. If more than two errors are provided, only the first two will be shown. Each error message has a character limit of 500; any message exceeding this limit will be truncated. Only plain text is supported for error messages. Any HTML or other formatting will be removed.
## Confirmation flow
Once a customer clicks Pay, the `paymentconfirmationrequested` event will be triggered on your frontend containing the `paymentMethod` token.
Execute the `ShopPayPaymentRequestSessionSubmit` mutation in order to confirm the payment. Once that is complete, call `session.completePaymentConfirmationRequest` on your frontend to continue. A payment complete event will be dispatched.
Based on payment capture configuration in Payments settings in the Shopify admin, the payment will be processed as a authorized or capture. If manual capture is configured, you must call the `orderCapture` mutation using the Shopify Admin API to finalize the payment. See [orderCapture](https://shopify.dev/docs/api/admin-graphql/latest/mutations/orderCapture) for more information.
When creating an order in Shopify, it may not be immediately available to query, and the orders/create webhook may not fire immediately. It's important to ensure that neither of these is required for real-time functionality of your app. See [Recovering from errors](#recovering-from-errors) for more information on making your app resilient to webhook delivery issues.
## API Reference: GraphQL Pre-payment
These mutations are used with the Storefront API to affect the Shop Pay payment request session.
### Example: ShopPayPaymentRequestSessionCreate
Details about the `ShopPayPaymentRequestSessionCreate` mutation can be found on the dedicated Storefront API [ShopPayPaymentRequestSessionCreate](/docs/api/storefront/latest/mutations/shopPayPaymentRequestSessionCreate) page.
```graphql
mutation shopPayPaymentRequestSessionCreate($sourceIdentifier: String!, $paymentRequest: ShopPayPaymentRequestInput!) {
shopPayPaymentRequestSessionCreate(sourceIdentifier: $sourceIdentifier, paymentRequest: $paymentRequest) {
shopPayPaymentRequestSession {
token
sourceIdentifier
checkoutUrl
paymentRequest {
…
}
}
userErrors {
field
message
}
}
}
```
```json
{
"sourceIdentifier": "xyz123",
"paymentRequest": {
// …
}
}
```
```json
{
"shopPayPaymentRequestSessionCreate": {
"shopPayPaymentRequestSession": {
"sourceIdentfier": "xyz123",
"token": "db4eede13822684b13a607823b7ba40d",
"checkoutUrl": "https://shop.app/checkout/1/spe/db4eede13822684b13a607823b7ba40d/shoppay",
"paymentRequest": {
// …
}
},
"userErrors": []
}
}
```
#### ShopPayPaymentRequestSessionCreate Arguments
| Argument | Type | Description |
| --- | --- | --- |
| sourceIdentifier | String! | A unique identifier for the source of the order. |
| paymentRequest | ShopPayPaymentRequestInput! | The payment request details. |
Source Identifier
The sourceIdentifier must be unique across all orders to ensure accurate tracking and referencing. For instance, it could be a unique ID associated with an order or checkout on your platform.
#### ShopPayPaymentRequestSession
| Field | Type | Description |
| --- | --- | --- |
| token | String | The unique token for the payment request session. |
| sourceIdentifier | String | A unique identifier for the source of the order. |
| checkoutUrl | String | The URL for the checkout associated with the payment request session. |
| paymentRequest | ShopPayPaymentRequest | The payment request associated with the session. |
#### UserErrors
| Field | Type | Description |
| --- | --- | --- |
| field | String | The field that caused the error. |
| message | String | The error message. |
### Example: ShopPayPaymentRequestSessionSubmit
Details about the `ShopPayPaymentRequestSessionSubmit` mutation can be found on the dedicated Storefront API [ShopPayPaymentRequestSessionSubmit](/docs/api/storefront/latest/mutations/shopPayPaymentRequestSessionSubmit) page.
```graphql
mutation shopPayPaymentRequestSessionSubmit($token: String!, $paymentRequest: ShopPayPaymentRequestInput!, $idempotencyKey: String!, $orderName: String) {
shopPayPaymentRequestSessionSubmit(token: $token, paymentRequest: $paymentRequest, idempotencyKey: $idempotencyKey, orderName: $orderName) {
paymentRequestReceipt {
token
processingStatusType
}
userErrors {
field
message
}
}
}
```
```json
{
"token": "db4eede13822684b13a607823b7ba40d",
"paymentRequest": {
…
},
"idempotencyKey": "REPLACE_ME_WITH_A_UNIQUE_KEY",
}
```
```json
{
"shopPayPaymentRequestSessionSubmit": {
"paymentRequestReceipt": {
"token": "a607823b7ba40ddb4eede13822684b13",
"processingStatusType": "ready"
},
"userErrors": []
}
}
```
#### Arguments
| Field | Type | Description |
| --- | --- | --- |
| token | String! | The unique token for the payment request session. |
| paymentRequest | ShopPayPaymentRequestInput! | The payment request details. |
| idempotencyKey | String! | A unique string (typically a UUID or similar identifier) that must be attached to the submit request to ensure that payment transactions occur only once. For more information, see [idempotent requests](https://shopify.dev/docs/api/usage/idempotent-requests). |
| orderName | String | The name to be assigned to the order that is created from the payment request. |
#### PaymentRequestReceipt
| Field | Type | Description |
| --- | --- | --- |
| token | String | The unique token for the payment request receipt. This will be different than session token. |
| processingStatusType | String | The processing status of the payment request. |
| paymentRequest | ShopPayPaymentRequest | The details of the payment request. |
#### UserErrors
| Field | Type | Description |
| --- | --- | --- |
| field | String | The field that caused the error. |
| message | String | The error message. |
## API Reference: GraphQL Post-payment
The post-payment process may involve capturing payments, adding tracking fulfillments, and issuing refunds. This section provides examples of how to use the Shopify GraphQL Admin API for these tasks.
### Payment Capture
Captures payment for an authorized transaction on an order if the Payments setting has been configured to manual. Using the order ID, you can fetch an [order](/docs/api/admin-graphql/latest/queries/order) and [orderTransaction](/docs/api/admin-graphql/latest/objects/OrderTransaction), then call [Admin API orderCapture mutation](/docs/api/admin-graphql/latest/mutations/orderCapture) to capture the authorized payment.
Here is an example of how to use the `orderCapture` mutation:
```graphql
mutation orderCapture($input: OrderCaptureInput!) {
orderCapture(input: $input) {
transaction {
id
amountSet {
shopMoney {
amount
currencyCode
}
presentmentMoney {
amount
currencyCode
}
}
kind
status
}
userErrors {
field
message
}
}
}
```
```json
{
"input": {
"amount": "10.00",
"currency": "USD",
"id": "gid://shopify/Order/1",
"parentTransactionId": "gid://shopify/OrderTransaction/2"
}
}
```
```json
{
"orderCapture": {
"transaction": {
"id": "gid://shopify/OrderTransaction/3",
"amountSet": {
"shopMoney": {
"amount": "10.00",
"currencyCode": "USD"
},
"presentmentMoney": {
"amount": "10.00",
"currencyCode": "USD"
}
},
"kind": "CAPTURE",
"status": "SUCCESS"
},
"userErrors": []
}
}
```
As a merchant using Shop Component, you have access to multi-capture, and are able to execute partial captures by providing any amount less than the currently un-captured amount.
For the first partial capture made against an authorization, you're also able to void the remaining authorization left after capturing an amount by including `"finalCapture": true` in your partial capture input. See details in the [orderCapture documentation](https://shopify.dev/docs/api/admin-graphql/latest/mutations/orderCapture#argument-input).
> Note:
Once an authorization has been partially captured, it can no longer be voided by any means. It must either be captured, or left to expire after the 7 to 30 day authorization period.
### Authorizations
With Extended Authorizations, you may capture payments beyond 7 days on most card types for a small fee. For more information, see [Credit card authorization periods](https://help.shopify.com/en/manual/payments/shop-pay/shopify-protect#credit-card-authorization-period).
You're also able to use the Order Authorization API to [void an authorization](https://shopify.dev/docs/api/admin-graphql/latest/mutations/transactionVoid) and then [replace it with a new authorization](https://shopify.dev/docs/api/admin-graphql/latest/mutations/orderCreateMandatePayment).
By combining partial captures using `"finalCapture": true`, with the Order Authorization API to create new authorizations, you're able to re-issue an authorization for the un-captured amount, while also minimizing times where authorized amounts are held on a customer's card for items they've cancelled before fulfillment.
While you may choose to re-issue authorizations immediately after void or expiration in order to maintain an active authorization, it isn't necessary. Authorizations can be re-issued on demand, as long as the total amount captured + total amount currently authorized is less than the order total.
### Fulfillment tracking
You can fetch an [order](/docs/api/admin-graphql/latest/queries/order) and [fulfillment order](/docs/api/admin-graphql/latest/objects/FulfillmentOrder) using the order ID.
If the order is shipped with a tracking number, then you must run the [`fulfillmentCreate`](/docs/api/admin-graphql/latest/mutations/fulfillmentCreate) mutation to update the tracking information and fulfill the order. You can make subsequent updates to the tracking information using the [`fulfillmentTrackingInfoUpdate`](/docs/api/admin-graphql/latest/mutations/fulfillmentTrackingInfoUpdate) mutation.
If the order is for store pickup, then you should instead run the [`fulfillmentOrderLineItemsPreparedForPickup`](/docs/api/admin-graphql/latest/mutations/fulfillmentOrderLineItemsPreparedForPickup) mutation to update the status.
Here is an example of how to use the `fulfillmentCreate` mutation:
```graphql
mutation fulfillmentCreate($fulfillment: FulfillmentInput!) {
fulfillmentCreate(fulfillment: $fulfillment) {
fulfillment {
id
status
trackingInfo(first: 10) {
company
number
url
}
}
userErrors {
field
message
}
}
}
```
```json
{
"fulfillment": {
"lineItemsByFulfillmentOrder": {
"fulfillmentOrderId": "gid://shopify/FulfillmentOrder/1"
},
"trackingInfo": {
"company": "UPS",
"number": "1Z001985YW99744790"
}
}
}
```
```json
{
"fulfillmentCreate": {
"fulfillment": {
"id": "gid://shopify/Fulfillment/1",
"status": "SUCCESS",
"trackingInfo": [
{
"company": "UPS",
"number": "1Z001985YW99744790",
"url": "https://www.ups.com/WebTracking?loc=en_US&requester=ST&trackNums=1Z001985YW99744790"
}
]
},
"userErrors": []
}
}
```
The following example shows how to use the `fulfillmentOrderLineItemsPreparedForPickup` mutation:
```graphql
mutation fulfillmentOrderLineItemsPreparedForPickup($input: FulfillmentOrderLineItemsPreparedForPickupInput!) {
fulfillmentOrderLineItemsPreparedForPickup(input: $input) {
userErrors {
field
message
}
}
}
```
```json
{
"input": {
"lineItemsByFulfillmentOrder": [
{
"fulfillmentOrderId": "gid://shopify/FulfillmentOrder/1046000776"
}
]
}
}
```
```json
{
"fulfillmentOrderLineItemsPreparedForPickup": {
"userErrors": []
}
}
```
### Refund creation
Using the order ID returned from a completed checkout, you can run the [`refundCreate`](/docs/api/admin-graphql/latest/mutations/refundCreate) mutation:
```graphql
mutation refundCreate($input: RefundInput!) {
refundCreate(input: $input) {
refund {
id
transactions(first: 10) {
nodes {
id
kind
status
}
}
}
userErrors {
field
message
}
}
}
```
```json
{
"input": {
"currency": "USD",
"note": "Customer returned item",
"orderId": "gid://shopify/Order/1",
"transactions": [
{
"amount": "10.00",
"gateway": "shopify_payments",
"kind": "REFUND",
"orderId": "gid://shopify/Order/1",
"parentId": "gid://shopify/OrderTransaction/2"
}
]
}
}
```
```json
{
"refundCreate": {
"refund": {
"id": "gid://shopify/Refund/1",
"transactions": {
"nodes": [
{
"id": "gid://shopify/OrderTransaction/3",
"kind": "REFUND",
"status": "SUCCESS"
}
]
}
},
"userErrors": []
}
}
```
### Cancelling and deleting orders
You can cancel orders in Shopify using the asynchronous [orderCancel mutation](https://shopify.dev/docs/api/admin-graphql/latest/mutations/orderCancel) which effectively stops the order from being further processed in Shopify:
```graphql
mutation OrderCancel($orderId: ID!, $notifyCustomer: Boolean, $refund: Boolean!, $restock: Boolean!, $reason: OrderCancelReason!, $staffNote: String) {
orderCancel(orderId: $orderId, notifyCustomer: $notifyCustomer, refund: $refund, restock: $restock, reason: $reason, staffNote: $staffNote) {
job {
id
done
}
jobResult {
id
done
}
orderCancelUserErrors {
field
message
code
}
}
}
```
```json
{
"orderId": "gid://shopify/Order/148977776",
"notifyCustomer": true,
"refund": true,
"restock": true,
"reason": "CUSTOMER",
"staffNote": "Wrong size. Customer reached out saying they already re-purchased the correct size."
}
```
```json
{
"orderCancel": {
"job": {
"id": "gid://shopify/Job/070bcd56-de0e-4985-bae8-c05be6365748",
"done": false
},
"jobResult": {
"id": "gid://shopify/OrderCancelJobResult/884324524",
"done": false
},
"orderCancelUserErrors": []
}
}
```
## Localization
Localization is a crucial aspect of providing a seamless shopping experience for customers around the globe. The Shop Component API supports localization to ensure that customers can interact with the checkout process in their preferred language.
### Setting the Locale
To set the locale, include the `locale` parameter when configuring the Shop Pay Payment Request. The `locale` parameter expects a valid ISO language code, with some locales followed by an ISO country code. See the [Supported Locales List](#supported-locales-list) section for the full list.
```javascript
window.ShopPay.PaymentRequest.configure({
shopId: 1,
clientId: "[REPLACE-ME.myshopify.com]",
locale: 'fr' // Example: Set locale to French
});
```
> Note:
If no locale is provided or if the provided locale is invalid, the default locale will be set to English (`en`).
### Supported Locales List
The following locales are supported by the Shop Component API:
| **Locale Code** | **Language** |
|-----------------|------------------------|
| `cs` | Czech |
| `da` | Danish |
| `de` | German |
| `en` | English (Default) |
| `es` | Spanish |
| `fi` | Finnish |
| `fr` | French |
| `hi` | Hindi |
| `it` | Italian |
| `ja` | Japanese |
| `ko` | Korean |
| `ms` | Malay |
| `nb` | Norwegian Bokmål |
| `nl` | Dutch |
| `pl` | Polish |
| `pt-BR` | Portuguese - Brazil |
| `pt-PT` | Portuguese - Portugal |
| `sv` | Swedish |
| `th` | Thai |
| `tr` | Turkish |
| `zh-CN` | Chinese - Simplified |
| `zh-TW` | Chinese - Traditional |
## Monitoring & Resiliency
It's highly recommended to instrument your integration with sufficient logging to gain insights into any errors thrown by your system. At a minimum, failure paths in your event handlers should all be considered, and notifications should alert your team of issues as needed.
Shopify provides webhook subscriptions and APIs enabling multiple ways for you to monitor activity in your shop. The below guidelines are applicable to Shop Component.
### Webhook Configuration
At a minimum, you should be to setting up the following webhooks:
| Webhook Topic | Description |
| --- | --- |
| `ORDERS_CREATE` | A webhook is sent every time an order is created. |
| `ORDER_TRANSACTIONS_CREATE` | A webhook is sent every time an order transaction is created. |
| `DISPUTES_CREATE` | A webhook is sent every time a dispute is created. This requires the `read_shopify_payments_disputes` scope on your custom app. |
| `DISPUTES_UPDATE` | A webhook is sent every time a dispute is updated. This requires the `read_shopify_payments_disputes` scope on your custom app. |
It's important to note that webhook delivery may be delayed, and must therefore never be depended on for real-time critical workflows such as completing a customer checkout.
To learn more, see [the webhook best practices guide](https://shopify.dev/docs/apps/webhooks/best-practices), and our webhook topic resources for [GraphQL](https://shopify.dev/docs/api/admin-graphql/latest/enums/WebhookSubscriptionTopic) and [REST](https://shopify.dev/docs/api/admin-rest/latest/resources/webhook#event-topics) APIs.
### Creating a Webhook Subscription
Example of creating new webhook subscription for the topic "ORDERS_CREATE" using the `webhookSubscriptionCreate` mutation:
```graphql
mutation webhookSubscriptionCreate($topic: WebhookSubscriptionTopic!, $webhookSubscription: WebhookSubscriptionInput!) {
webhookSubscriptionCreate(topic: $topic, webhookSubscription: $webhookSubscription) {
webhookSubscription {
id
topic
format
endpoint {
__typename
... on WebhookHttpEndpoint {
callbackUrl
}
}
}
userErrors {
field
message
}
}
}
```
```json
{
"topic": "ORDERS_CREATE",
"webhookSubscription": {
"callbackUrl": "https://yoursite.com/webhooks/orders_create",
"format": "JSON"
}
}
```
```json
{
"webhookSubscriptionCreate": {
"webhookSubscription": {
"id": "gid://shopify/WebhookSubscription/1",
"topic": "ORDERS_CREATE",
"format": "JSON",
"endpoint": {
"__typename": "WebhookHttpEndpoint",
"callbackUrl": "https://yoursite.com/webhooks/orders_create"
}
},
"userErrors": []
}
}
```
### Handling Disputes
A dispute, also known as a chargeback or inquiry, occurs when a customer questions the legitimacy of a charge with their financial institution.
To effectively manage disputes, you must either subscribe to the appropriate webhook topics and [use the Shopify Admin API as necessary](https://shopify.dev/changelog/read-and-write-disputes-and-dispute-evidence-in-the-graphql-and-rest-admin-api), or manage the disputes through the Shopify admin.
When a dispute is filed, you're able to provide additional information to support the legitimacy of the charge before the time limit. In any case, Shopify will ensure that evidence is submitted on your behalf, whether you take action or not.
Orders may also be eligible for [Shopify Protect](https://help.shopify.com/en/manual/payments/shop-pay/shopify-protect), in which case Shopify will reimburse you for the disputed amount and chargeback fee if it is lost.
For more information on dispute management, see the [Shopify Payments Disputes Documentation](https://help.shopify.com/en/manual/payments/shopify-payments/chargebacks).
### Order Risks
Orders in Shopify will undergo a risk assessment after order creation. You can either [query the OrderRiskSummary](https://shopify.dev/docs/api/admin-graphql/latest/objects/OrderRiskSummary), or you can subscribe to the `ORDERS_RISK_ASSESSMENT_CHANGED` webhook. Orders can trigger automation events using [Shopify Flow](https://apps.shopify.com/flow) – see the [flow reference risk examples](https://help.shopify.com/en/manual/shopify-flow/reference/examples#risk) for details.
### Recovering from errors
Although an order created event will be fired client-side when an order is completed, it's possible that a customer may close the window before the event is dispatched. In order to reconcile in such cases it is recommend to have a reconciliation job running on a schedule.
### Reconciliation job
While webhook deliveries are recommended as the primary method for Shopify to trigger actions in your system, reconciliation jobs should always be implemented as well, as they serve multiple purposes:
* In case the Shop Pay window is closed before the `paymentcomplete` event is dispatched
* As a backup to webhooks, since webhooks may fail to be processed
* To retrieve data which may not otherwise be available via webhook subscription
#### Retrieving order data using the source identifier
You can find [shopPayPaymentRequestReceipts](/docs/api/admin-graphql/unstable/queries/shopPayPaymentRequestReceipts) by their `source_identifier` (provided on `ShopPayRequestSessionCreate` mutation), which should correspond to the order in your system. For example, if the source identifier provided by your system for a given order was `your-source-id-1`, then you could issue a GraphQL request like below:
```graphql
{
shopPayPaymentRequestReceipts(first:10, query: "source_identifier:'your-source-id-1'") {
nodes {
token
sourceIdentifier
processingStatus {
state
message
errorCode
}
order {
id
sourceIdentifier
transactions(first: 10) {
id
kind
errorCode
}
fulfillmentOrders(first: 10) {
nodes {
id
}
}
}
paymentRequest {
total {
amount
currencyCode
}
}
}
}
}
```
Note that while the above example request could result in multiple matching receipts, there will only be one corresponding order for a successfully completed receipt. The order may have multiple transactions (including failed payment attempts), fulfillmentOrders and lineItems.
Because of this, your system must filter the results received. For example with transactions you would filter by `kind: "authorization"` and `status: "success"` to identify the transaction authorization ID needed when capturing payment.
It's recommended to modify this example query to only retrieve the data required by your system, and introduce [pagination](https://shopify.dev/docs/api/usage/pagination-graphql) where necessary.
#### Retrieving order data using the receipt token
Alternatively, order data can be retrieved using the `shopPayPaymentRequestReceipt` query. The receipt token is returned from the [`ShopPayPaymentRequestSessionSubmit`](#example-shoppaypaymentrequestsessionsubmit) mutation.
This query can be used to find the status of the payment request receipt. The status can be `processing`, `completed`, `action_required` (for example, if the customer needs to complete a 3DS authentication. This is automatically handled by Shop Pay popup), or `failed`. The `processingStatus` `message` and `errorCode` can be used to provide more information about the status for failed receipts.
```graphql
query {
shopPayPaymentRequestReceipt(token: "") {
token
sourceIdentifier
processingStatus {
state
message
errorCode
}
order {
id
sourceIdentifier
transactions(first: 10) {
id
kind
errorCode
}
fulfillmentOrders(first: 10) {
nodes {
id
}
}
}
paymentRequest {
total {
amount
currencyCode
}
}
}
}
```
## Additional resources