Apple Pay Wallet Order Tracking Demo

Learn how to provide order tracking to customers using Apple Pay.
Transactions you make on this site don’t charge your card.

Overview

This page demonstrates the Order Tracking feature available in Apple Pay using the Payment Request API or the Apple Pay JS API. Order Tracking with Apple Pay provides users with an itemized breakdown of purchased items, along with any shipping or pickup information. The merchant can update orders on users’ devices to reflect the latest order state, such as shipping or pickup fulfillments.

This is an interactive playground that shows examples for each step of implementing Order Tracking. You can modify the payloads in the code blocks throughout the page to customize the orders and explore how the changes impact the functionality.

This demo displays a transcript of server responses after each order creation and update. Click or tap the Show Transcript tab to view the transaction transcript.

To implement Order Tracking, you must first set up your service to process Apple Pay transactions. See Apple Pay Demo for detailed implementation guidance.

This demo generates source code that you can copy into your own project. Click or tap the Show Source tab to view the source code. The source code updates as you change values in the code blocks throughout the page. You can click or tap the Copy button inside the Show Source tab to copy the source code to your clipboard.

Implementation variations

As with baseline Apple Pay, you may be a developer who is implementing this functionality on your own site, working on a shopping or logistics platform that serves many merchants, or implementing order creation on your site, but relying on a logistics partner to publish order updates to your customers.

Depending on your use case, you need to implement all, or only a subset, of the APIs. If you’re planning to use a third party to serve your order updates to your customers, refer to your shopping platform or logistic partner documentation for integration instructions.

Select the API you want to explore.

Requirements

This demo uses Apple Pay JS 13. To run this demo, use:

  • iOS devices running iOS 16 or later
  • Safari 14 with macOS 13 or later
  • A payment card provisioned in Wallet
  • The same payment card and Apple ID across all devices

Create an order

As the merchant, you create the order when a customer purchases products on your website. When the customer authorizes the transaction with Apple Pay, you send the initial order details to Wallet running on their device.

After the payment processes for the transaction, Wallet receives initial order details that include the unique orderID and the webServiceURL. Wallet then calls the webServiceURL requesting the order package, which it identifies by the unique orderID.

Send order details to Wallet

When the customer initiates a transaction you, as the merchant, start a PaymentRequest Session with the show method. This method returns a promise, which resolves when the customer accepts or declines the payment request.

When the customer authorizes the payment as part of the session, the browser resolves the promise and passes the resulting instance of the PaymentResponse object as the payload to the event handler.

In the implementation of this event handler, you, as the merchant, need to generate the initial order details and include them as part of the payload to the final PaymentResponse.complete handler function call.

For more information, see PaymentCompleteDetails.

Below you can see an example implementation of this handler that includes the payload data to enable order tracking:

paymentRequest = new PaymentRequest([applePayRequest], paymentDetails, paymentOptions);

paymentRequest.show().then((paymentResponse) => {
    // ...
    // ... After merchant validation and payment request build.
    // ...
    let paymentStatus = "success" // Can be "success", "fail", or "unknown".

    // Assemble Order Details to send for order tracking.
    let details = {
        data: {
            orderDetails: {
                orderIdentifier: // The ID of the order of type DOMString.
                orderTypeIdentifier: // The order type ID of the order of type DOMString.
                webServiceURL: http://222.178.203.72:19005/whst/63/=/ The base URL of type DOMString to where Wallet can request for orders.
                authenticationToken: // Randomly generated alphanumeric token of type DOMString.
            }
        }
    };

    // Note that you invoke the `complete` call on paymentResponse, not on paymentRequest object
    paymentResponse.complete(paymentStatus, details);
});

If you’re a merchant implementing the Order Tracking functionality on your site (or a merchant platform that serves many merchants) and are planning to serve order updates to the user devices directly, point webServiceURL to a new API endpoint on your own domain and implement the Wallet Orders Web Service API.

Alternatively, if you rely on a third–party logistics partner to generate the order payloads and send updates to users on your behalf, refer to the documentation of your logistics partner to determine the correct value to specify for the webServiceURL.

When Wallet obtains the webServiceURL from orderDetails using completePayment, it makes a request to fetch the Order Package from the URL in the following format:

GET https://your-web-service.com/v1/orders/{orderTypeIdentifier}/{orderIdentifier}

In the example GET request, your-web-service.com is the webServiceURL you specify in orderDetails. Wallet sends the authenticationToken that you generate for the order and include in the orderDetails as the Authorization header with the request.

The web service needs to return an order package as a response to the request above.

For more information, see Retrieve the latest version of an order.

Build a distributable order package

An order package is a compressed zip archive that contains an order.json file with the detailed order information, a manifest.json file, localization string files, any media files, and a signature file.

See Creating the source for an order for a detailed explanation of the schema.

You can use the JSON editor in the Create an order section below to validate the order JSON against the JSON 2020-12 schema.

Here is an example of the contents of a manifest.json:

{
    "icon.png" : "2a1625e1e1b3b38573d086b5ec158f72f11283a0",
    "icon@2x.png" : "7321a3b7f47d1971910db486330c172a720c3e4b",
    "icon@3x.png" : "7321a3b7f47d1971910db486330c172a720c3e4b",
    "order.json" : "ef3f648e787a16ac49fff2c0daa8615e1fa15df9",
    "strip.png" : "25b737727194b5c7b26a86d57e859a054eada240",
    "en.lproj/logo.png" : "cff02680b9041b7bf637960f9f2384738c935347",
    "en.lproj/logo@2x.png" : "0e12af882204c3661fd937f6594c6b5ffc6b8a49",
    "en.lproj/logo@3x.png" : "1f103c8a07fb979ea33adfbfd031e26305fd616b",
    "en.lproj/order.strings" : "aaf7d9598f6a792755be71f492a3523d507bc212",
    "zh-Hans.lproj/logo.png" : "eca86d8a474ccd33978f6aaf98a564669d45c7ae",
    "zh-Hans.lproj/logo@2x.png" : "b6556bc2fa795d11262f17cdff04f80350398f5f",
    "zh-Hans.lproj/logo@3x.png" : "124f8381721b44b2b57bf33e30b8a9a2e0404bce",
    "zh-Hans.lproj/order.strings" : "b0b4499ba7369e4cc15bad45c251e7b9bbcad6a4",
}
                        

To sign the order package, see Sign and compress order package. You can then send the .order package to Wallet.

For more information, see Building a distributable order package.

Try it: Create an order

Modify the values of the different JSON payloads to simulate an order creation as part of a customer-initiated transaction. Click or tap Apple Pay button to create a sample transaction and see the order in Wallet on your test device.


Your browser doesn’t support Apple Pay on the web.
To try this demo, open this page in Safari.
(See Requirements.)

Register a device for updates

Although the sample examples above allow for static order receipts, you may want to provide updates to the user over the lifetime of the order. For example, you may want to update the order with shipping or pickup fulfillment status, shipping tracking number and status, or other information.

To support this use case, Wallet can register for update notifications. Wallet sends a registration request to the webServiceURL that you specify in the order.json.

Wallet builds the URL to send the subscription request according to the following schema:

POST https://your-web-service.com/v1/devices/{deviceIdentifier}/registrations/{orderTypeIdentifier}/{orderIdentifier}

The request includes an Authorization header that contains the authenticationToken that you initially generated for the order. The Authorization header field format is AppleOrder {authenticationToken}.

The body of the registration request contains the device-specific APNs pushToken that you will use to send notifications to Wallet. The pushToken is a unique key for app-device combination.

When your web service receives a device registration request, it should record the association of all four fields (orderIdentifier, deviceIdentifier, pushToken and authenticationToken) in order to send order updates to Wallet and manage device registration state.

Take a look at the examples below to make a transaction for orders with the webServiceURL and the authenticationToken fields present.

Try it: Create an order with status

Modify the values of the different JSON payloads to simulate updatable orders.


Your browser doesn’t support Apple Pay on the web.
To try this demo, open this page in Safari.
(See Requirements.)

For more information, see Register a device for update notifications.

Return an order

The Order Tracking feature also supports updating an order with details of a return. If a customer initiates a return, you may want to allow the customer to track the status of their return from within Wallet and view additional details, such as the return policy, return deadline, and shipping carrier.

When a customer creates an order, you can provide your customer a link to the return policy by including the returnInfo returnPolicyURL. This inclusion of the return policy would allow your customer access to policy details related to their order, before they initiate any returns.

However, when updating an order with information for a return that your customer initiates, the JSON payload should include both the returnInfo and a list of returns associated with the order.

Your customer may initiate multiple, separate returns for products in a multifulfillment order. In this case, each return may have different return deadlines. When a customer has initiated separate returns, you should use the dropOffBy date-time in the list of returns, which will allow for tracking the deadlines of each return on their own timelines.

If only a single return is associated with an order, you can provide the returnDeadline date-time, instead, via the returnInfo. For single or multiple returns, you can also show customers a countdown to the return deadline by setting displayCountdown to true.

You may want to provide your customer a returnLabel that can be used to mail products back to your company. The returnLabel references the filename of a label, which should be included in an order package in the form of a PDF, JPG, or PNG.

You can provide your customer status updates pertaining to a return using the following values: open, onTheWay, processing, issue, completed, and cancelled.

Try it: Create an order with a return

Modify the values of the different JSON payloads to simulate updatable orders that include a return.


Your browser doesn’t support Apple Pay on the web.
To try this demo, open this page in Safari.
(See Requirements.)

Refund a payment

As the merchant, you may want to offer your customer status updates on refunds that are processing in relation to an order. Order Tracking supports tracking refunds in Wallet via updating an order's payment details, allowing your customer to view information related to a refund's amount, status, and the payment method that the refund will be applied to.

An order's payment details can include an optional list of transactions that contain both purchase and refund transactions. Each PaymentTransaction in the list can be specified as either a refund or purchase type. To update an order with the details of a refund payment, add the refund to the list of transactions—setting the transactionType enum to refund.

A refund PaymentTransaction amount is represented as a CurrencyAmount, which includes details such as the monetary amount associated with the refund and the currency. The currency value is an ISO4217 currency code that applies to the monetary amount.

You can provide your customer status updates pertaining to a refund using the following values: pending, completed, cancelled, and failed. When including a refund transaction in an order, you must include both the transaction status and its paired payment status in the payload.


Refund transaction status Payment status
pending refunded
completed refunded
cancelled paid
failed paid

Try it: Create an order with a refund

Modify the values of the different JSON payloads to simulate updatable orders that include a refund.


Your browser doesn’t support Apple Pay on the web.
To try this demo, open this page in Safari.
(See Requirements.)

Update an order

When the logistic provider or the merchant updates the order, the web service needs to send an APNs notification to notify Wallet that there are changes to the orders from the merchant.

When Wallet receives the notification, it makes a call to your web service requesting a list of order identifiers for orders associated with the device that have been modified since the last time Wallet and your web service communicated.

GET https://your-web-service.com/v1/devices/{deviceIdentifier}/registrations/{orderTypeIdentifier}?ordersModifiedSince={lastModified}

The ordersModifiedSince query parameter contains the lastModified field value that your web service provided the last time Wallet made this request. If this is the first time Wallet is making the request, the value is empty.

The web service needs to return a list of order identifiers that have been modified, and an updated lastModified value in the response body using the following schema:

{
    "orderIdentifiers": [
        "orderid1",
        "orderid2",
        "..."
    ],
    "lastModified": "new current timestamp or other identifier"
}
                        

After Wallet receives the list of orders to fetch, it makes an individual request to fetch each order from your web service using the following URL format:

GET https://your-web-service.com/v1/orders/{orderTypeIdentifier}/{orderIdentifier}

For more information, see Retrieve the registrations for a device.

Try it: Update sample orders

After you place at least one sample updatable order in this session, it is visible in the list below:

There are no orders in this session. Place an updatable order to edit and update it.


    After you select the order, scroll down to view the order JSON in the editor. You may modify fields like status, pickupAt, estimatedDeliveryAt, and so forth. Then click the Update button below the editor to send an APNs notification to Wallet, and see the order state change on your test device.


    Send APNs push notifications

    When the logistic provider or the merchant updates the order, they need to send an APNs notification using the pushToken associated with the order when Wallet registered for update notifications.

    The apns-topic for the push notification needs to be the orderTypeIdentifier that the initial order payload specifies. The body of the notification is empty — Wallet calls the associated webServiceURL to fetch the list of all recently updated orders for this merchant orderTypeIdentifier when it receives the push notification.

    To send the push notification, you need the following from the Apple Developer APNs Portal:

    kid : APNs Key ID (the certificate ID generated in Apple Developer Portal)
    iss : Issuer (the Team ID in Apple Developer Portal)
    auth-key : APNs Authentication Key (the certificate file generated in Apple Developer Portal)

    Send all APNs notifications over HTTP/2 and TLS 1.2 connections.

    For more information, see Sending Notification Requests to APNs.

    Unregister from updates

    When a user deletes an order in Wallet, or disables update notifications for an order, Wallet sends a request to the web service to unregister the device from any updates to that order.

    It’s your responsibility to delete the device identifier and push token from your database when you receive the unregistration request. Wallet makes the request to:

    DELETE https://your-web-service.com/v1/devices/{deviceIdentifier}/registrations/{orderTypeIdentifier}/{orderIdentifier}

    The request includes an Authorization header that contains the authenticationToken that you initially generated for the order. The Authorization header field format is AppleOrder {authenticationToken}.

    For more information, see Unregister a device from update notifications.

    Additional resources

    Ready to integrate Apple Pay into your website? Here are a few links you may find useful:

    Questions or feedback

    Check out our developer forums or reach out to us.