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.
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); });
Note
The Order Details payload above is different from an Order Package. The Order Details payload is how you, as the merchant, tell Wallet where to fetch the Order Package. The Order Package in the following section is what Wallet fetches and parses to display the order information.
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.
Provide a testing environment
If you’re a platform generating and serving orders on behalf of merchants, provide your merchants with a testing environment, so they can test Order Tracking and validate the order format and presentation for their storefronts.
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", }
Note
Don’t include metadata files that aren’t part of the order format, such as
the .DS_Store
file, in the manifest or distributable order package.
To sign the order package, see Sign and compress order package.
You can then send the .order
package to Wallet.
Note
See the Track in Wallet button documentation to allow users to download the order package directly from their browser.
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.
Note
Users can process transactions including order information on macOS 13 and later, but the orders aren’t visible in the macOS UI — the order will appear in Wallet on users’ devices running iOS 16 or later.
If a user performs the transaction using an earlier version of macOS or iOS, their device ignores the order payload information.
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
.
Note
If a user has more than one device, you may see multiple unique device registrations for the same order. As the order receipt syncs between all of the users’ devices, each device subscribes to order updates.
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.
Note
Wallet will only perform the request your web serivce to register a device for order updates if
you include the webServiceURL
and
authenticationToken
fields in the top-level of the
order.json
.
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.
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.
Note
The total size of an order package must be below 5MB. For more information, see Build a distributable order package.
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.
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 |
Note
Though the payment
status
field is marked as deprecated, this field is currently required to support backwards
compatibility for order payloads that include a
payment
object.
Try it: Create an order with a refund
Modify the values of the different JSON payloads to simulate updatable orders that include a refund.
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.
Note
Best practice is to use a standard timestamp for this field in
ISO8601
format, but you can choose to use any value that
works best for your circumstances.
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.
- Development server: api.sandbox.push.apple.com:443
- Production server: api.push.apple.com:443
For more information, see Sending Notification Requests to APNs.
Important
To accept log entries from user devices, the web service API needs to implement the logging endpoint at:
POST https://your-web-service.com/v1/log.
This endpoint is how Wallet notifies you about any problems processing order packages. If you don’t implement the endpoint, or the endpoint doesn’t return a 200 OK response when Wallet sends log messages to it, Wallet will not process the push notifications for your order type ID.
For more information, see Receive log messages.
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.