> ## Documentation Index
> Fetch the complete documentation index at: https://developer.hellgate.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Tokenize Apple Pay

> Tokenize Apple Pay payments and manage the resulting wallet tokens

Apple Pay is a device wallet supported by Guardian [wallet tokens](/products/guardian/tokens/wallet-tokens/overview). You pass the encrypted Apple Pay payload to Guardian, which verifies, decrypts, and stores the credential server-side, so the decrypted card data never touches your systems.

Unlike a card-on-file credential, an Apple Pay payment always yields a **device-bound token**: a device PAN (DPAN) with a single-use cryptogram and ECI. Guardian never sees or stores the underlying funding PAN.

## Operating Modes

Every Guardian deployment runs Apple Pay in one of two modes, set by the operator:

* **`self_managed`** (the default): you upload your own Apple identity to Guardian and manage the certificates yourself. This is the flow this page describes. The RSA identity certificate is a **merchant identity certificate**.
* **`sf_operated`**: Starfish operates the Apple Developer relationship, and the Apple identity and certificates come from Guardian's configuration (mounted by Starfish). On these deployments the settings-upload and certificate-management endpoints are disabled and return `409` with the classifier `APPLE_PAY_CERT_MANAGEMENT_UNAVAILABLE`. Only domain registration and the runtime flow (sessions, tokenize, forward) are available to you. Here the same RSA identity certificate is a **platform integrator identity certificate**.

You can check which mode an instance runs in with [Get settings](/products/guardian/api-reference/wallet/get-settings).

## Prerequisites

Apple Pay encrypts every payload for a specific merchant and requires Apple to trust your domain before the browser will present the payment sheet. Before you can tokenize, complete the one-time setup below. All setup endpoints are administrative and separate from the runtime tokenization flow.

<Steps>
  <Step title="Upload your Apple Pay settings">
    Before Guardian can generate CSRs, register domains, or validate sessions, it needs your Apple identity. Call [Update settings](/products/guardian/api-reference/wallet/update-settings) with:

    * `merchant_identifier`: your Apple Pay merchant identifier.
    * `display_name`: the merchant display name shown in the Apple Pay sheet.
    * `domain_association_content`: the byte-exact body of the domain-association file Apple issued, which Guardian serves verbatim.
    * `csr_common_name`: the common name to embed in the CSRs Guardian generates.

    Guardian reads the merchant identifier, display name, CSR common name, and served domain-association body from these settings. The upload is a partial update: fields you omit keep their current values. Until all are uploaded, the steps below return `400` with the classifier `APPLE_PAY_NOT_CONFIGURED`.

    On Starfish-operated (`sf_operated`) instances this step and the certificate steps below are managed by Starfish; those endpoints return `409` with the classifier `APPLE_PAY_CERT_MANAGEMENT_UNAVAILABLE`.
  </Step>

  <Step title="Register your payment processing certificate">
    Guardian holds the private key inside its PCI boundary and only ever emits a signing request. Call [Create certificates](/products/guardian/api-reference/wallet/create-certificates) to have Guardian generate the certificate signing requests (CSRs): an EC **payment processing** CSR and an RSA **merchant identity** CSR.

    Submit each `csr_pem` to Apple in the [Apple Developer](https://developer.apple.com/account/resources/certificates/list) portal, download the signed certificates, and return them with [Upload a certificate](/products/guardian/api-reference/wallet/upload-a-certificate). Once uploaded, the certificate moves to `active` and becomes the one Guardian uses to decrypt payloads and authenticate to Apple.
  </Step>

  <Step title="Register your domain">
    Every domain that shows the Apple Pay button must be registered with Apple. Fetch the domain-association file from your Guardian instance at [`GET /.well-known/apple-developer-merchantid-domain-association.txt`](/products/guardian/api-reference/wallet/get-association-file) (public, no authentication) and serve it from your domain at the same path. Register the domain in the [Apple Developer](https://developer.apple.com/account/resources/identifiers/list/merchant) portal, where Apple fetches that file to attest your ownership.

    Then call [Register a domain](/products/guardian/api-reference/wallet/register-a-domain) with the fully-qualified domain, for example `pay.example.com`. On a `self_managed` instance Guardian trusts your attestation and marks the domain `verified` immediately. On `sf_operated` instances Guardian instead registers the domain with Apple's Web Merchant Registration API in the background; the domain starts as `pending` and moves to `verified` once Apple accepts it. [Verify a domain](/products/guardian/api-reference/wallet/verify-a-domain) re-triggers verification for a `pending` or `failed` domain.
  </Step>
</Steps>

Guardian verifies every payload's signature against Apple's root certificate authority, which is seeded on your instance; no setup is needed. If Apple ever rotates its root CA, replace the trust anchor with [Replace trust anchor](/products/guardian/api-reference/wallet/replace-trust-anchor) and inspect the active one with [Get trust anchor](/products/guardian/api-reference/wallet/get-trust-anchor).

## Merchant Validation

When a customer opens the Apple Pay sheet in a browser, Apple fires `onvalidatemerchant` with a validation URL. Your client sends that to your backend, which asks Guardian to complete the exchange with Apple on your behalf. Call [Validate Apple Pay session](/products/guardian/api-reference/wallet/validate-apple-pay-session) with the `domain_name` (a verified domain); Guardian reads your merchant identifier and display name from the [Apple Pay settings](/products/guardian/api-reference/wallet/get-settings). Guardian performs the mTLS handshake with Apple using the active identity certificate and returns Apple's session object verbatim. Pass it straight to `session.completeMerchantValidation(...)` in the browser.

A request for an unregistered or unverified domain returns `422` with the classifier `APPLE_PAY_DOMAIN_NOT_VERIFIED`. If Apple rejects the validation, Guardian returns `502` with `APPLE_PAY_SESSION_ERROR`; if no active identity certificate exists, `500` with `APPLE_PAY_NO_ACTIVE_CERTIFICATE`.

## Tokenizing an Apple Pay Payment

When the customer authorizes the payment, the Apple Pay JS API hands your client a `PKPaymentToken` whose `paymentData` is the encrypted `EC_v1` envelope. Send that envelope to [Tokenize Apple Pay](/products/guardian/api-reference/wallet/tokenize-apple-pay) exactly as Apple returns it, as the `payment_data` field. Guardian verifies the signature against Apple's trusted certificates, decrypts the payload with your active payment processing certificate, and stores the credential as a wallet token.

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant C as Customer
    participant M as Merchant
    participant A as Apple Pay
    participant H as Guardian
    participant P as PSP / Acquirer

    C->>+A: Open Apple Pay sheet
    A->>A: onvalidatemerchant
    A->>+M: Validation URL
    M->>+H: POST /api/wallet/apple-pay/sessions
    H->>+A: Merchant validation over mTLS
    A->>-H: Merchant session
    H->>-M: Merchant session
    M->>-A: completeMerchantValidation
    C->>A: Authorize payment
    A->>-M: PKPaymentToken (EC_v1 payment_data)
    M->>+H: POST /api/wallet/apple-pay/tokenize
    H->>H: Verify signature, decrypt, store
    H->>-M: Wallet token (id, card)
    M->>+H: POST /api/wallet/{id}/forward
    H->>+P: Request with card data injected
    P->>-H: Authorization result
    H->>-M: Authorization result
```

Tokenization is idempotent on the encrypted payload: resubmitting the same envelope returns the existing wallet token rather than creating a duplicate. If that payload's wallet token was already deleted, the request returns `409` with the classifier `APPLE_PAY_TOKEN_DELETED`.

Rejected envelopes return `422` with a classifier naming the cause:

| Classifier                      | Cause                                                                                                                                          |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `APPLE_PAY_SIGNATURE_INVALID`   | The signature could not be verified against the trusted certificate.                                                                           |
| `APPLE_PAY_UNKNOWN_CERTIFICATE` | The payload was encrypted for a certificate not registered on this instance.                                                                   |
| `APPLE_PAY_TOKEN_EXPIRED`       | The payload has expired.                                                                                                                       |
| `APPLE_PAY_MALFORMED_TOKEN`     | A required field is missing or the payload is malformed. Guardian's generic missing-field classifier, shared by the other Apple Pay endpoints. |

If no active payment processing certificate exists, tokenization returns `500` with the classifier `APPLE_PAY_NO_ACTIVE_CERTIFICATE`.

## Forwarding

[Forwarding a wallet token](/products/guardian/tokens/wallet-tokens/overview#forwarding-wallet-tokens) works the same for every wallet; this section lists the placeholders and rules specific to Apple Pay. An Apple Pay token is a device-bound token, so it carries the following placeholders:

| Placeholder          | Description                    |
| -------------------- | ------------------------------ |
| `{{ dpan }}`         | The device PAN.                |
| `{{ cryptogram }}`   | The 3-D Secure cryptogram.     |
| `{{ eci }}`          | Electronic Commerce Indicator. |
| `{{ expiry_month }}` | Card expiry month.             |
| `{{ expiry_year }}`  | Card expiry year.              |

An Apple Pay token is **single-use**: the first successful forward consumes its cryptogram, and later attempts return `400` with the classifier `CRYPTOGRAM_CONSUMED`. If your template references a placeholder the token does not carry, the forward is rejected with `422` and the classifier `DESTINATION_POLICY_VIOLATION`; a placeholder the token does carry but that has no value on this specific credential returns `422` with `PLACEHOLDER_VALUE_MISSING`. Both name the offending placeholder.

Because an Apple Pay token carries no funding PAN, it cannot be promoted to a network token.
