# Apple Pay

_Integrate Apple Pay with Evervault to capture encrypted payment credentials._

![An illustration of an Apple Pay payment]()

Apple Pay allows customers to securely complete payments using credit or debit cards linked to their Apple account. Evervault has built-in support for Apple Pay. Our Apple Pay component will intercept the Apple Pay token and provide you with direct access to the encrypted payment method, which can then be sent to any payment processor using [Relay](/relay).

> **Sandbox testing**
>
> You can use [Sandbox apps](/developers/sandbox) to test Apple Pay end-to-end without charging a real card. In sandbox, based on the brand of the card the customer selects in their Apple Wallet, the network token is replaced with a [test card](/cards/apple-pay#testing-sandbox) and the rest of the flow proceeds as normal. See [Testing (sandbox)](#testing-sandbox) for more details.

## Getting started

All users of Apple pay must adhere to the [Apple Pay Terms and Conditions](https://www.apple.com/legal/internet-services/apple-pay-wallet/us/).

#### Browser

### Create a merchant

Before you can use Apple Pay, you need to create a Merchant record to use for the transaction. You can create a merchant from inside the payments tab in the [Evervault Dashboard](https://app.evervault.com) or via the [Merchants API](/api#createMerchant).

### Verify your domain with Apple

After creating a merchant, Apple needs to verify the domains associated with it. You can add and verify your domains using the Evervault Dashboard under **Payments** > **Apple Pay**.

Alternatively, you can serve [this identifier file](/apple-pay/apple-developer-merchantid-domain-association) from `/.well-known/apple-developer-merchantid-domain-association` on your domain, then register your domain via the [Merchant API](/api#updateMerchant).

You can check the status of your domain verification with Apple via the Dashboard or by using the [Merchant API](/api#merchant). **It may take up to 10 minutes for the verification to complete.**

> **Reverification**
>
> Once a domain is verified, you must ensure that the validation token is always
>   available at the specified URL. If the validation token is not available when
>   Apple periodically attempts to retrieve it, Apple will not be able to verify
>   the domain, and Apple Pay will not work on your website.

### Install the SDK

Our [JavaScript SDK](/sdks/javascript) is distributed from our CDN, and can be installed by placing this script tag in the head of your HTML file. The SDK must be loaded directly from our CDN and cannot be bundled with your application or self hosted.

```html
<script src="https://js.evervault.com/v2"></script>
```

Once the SDK is installed, initialize it using your Team ID and App ID. You can find these in the [Evervault Dashboard](https://app.evervault.com).

```javascript
const evervault = new Evervault("<TEAM_ID>", "<APP_ID>");
```

You can also install Evervault via the `@evervault/js` package on npm. This package is a light wrapper which handles loading the SDK from our CDN and also provides TypeScript definitions.

```javascript
import { loadEvervault } from "@evervault/js";

const evervault = loadEvervault("<TEAM_ID>", "<APP_ID>");
```

#### Frequently Asked Questions

##### Why does the SDK need to be loaded from the CDN?

The SDK must be loaded directly from our CDN in order to be PCI Compliant.

##### How do I get my Team ID and App ID?

You can find your Team ID and App ID in the [Evervault Dashboard](https://app.evervault.com).

##### Can I load the SDK asynchronously?

You can load the SDK asynchronously using the `async` attribute on the script tag to prevent blocking the loading of your page. However, it is important to note that you will need to wait for the SDK to load before making any API calls.

    ```html
    <!DOCTYPE html>
    <html>
      <head>
        <script src="https://js.evervault.com/v2" onload="onEvervaultReady()" async></script>
        <script>
          function onEvervaultReady() {
            const evervault = new Evervault('<TEAM_ID>', '<APP_ID>');
          }
        </script>
      </head>
    </html>
    ```

### Create a transaction

Next, you will need to create a transaction to describe the payment you want to process. You will need to provide the amount, currency, country, and merchant details for the transaction. With Apple Pay a transaction can be a Payment Transaction or a Disbursement Transaction. You can pass either transaction type to the Apple Pay component.

### Mount the Apple Pay component

Now that you have created a transaction, you can create and mount the Apple Pay component to display the Apple Pay button to your users. The Apple Pay component takes the transaction you created as a first argument and an options object with a `process` function that will be called with the encrypted payment method when the user completes the payment. The process function is an asynchronous function that takes the encrypted payment method as the first argument and an object with a `fail` function as the second argument. The `fail` function can be called with an error message to display an error to the user.

```javascript
const apple = evervault.ui.applePay(transaction, {
  process: async (paymentMethod, { fail }) => {
    try {
      console.log(paymentMethod.networkToken.number);
      // ev:Tk9D:hY5KJanIPOHBoI8S:AsnnjRl0FDe2zEddBAQG/eI2vN+b...:$

      // Send the encrypted payment method to your backend for processing
    } catch (error) {
      fail({
        message: "Cannot pay with payment credentials",
      });
    }
  },
});

apple.on("cancel", () => {
  console.log("Apple Pay canceled");
});

apple.on("error", (error) => {
  console.error("Apple Pay error", error);
});

apple.on("success", () => {
  console.log("Apple Pay success");
});

apple.on("ready", () => {
  console.log("Apple Pay button is ready!");
});

const availability = await apple.availability();

if (availability === "available") {
  // Mount the Apple Pay component to a container element
  apple.mount("#apple-pay");
} else {
  // Apple pay is not available on the device
}
```

### Abort an active session

If the user changes their shipping address to a country that uses a different currency, you cannot update the currency on an open Apple Pay sheet. Call `abort()` to dismiss the sheet, update your transaction with the new currency and country, then let the user tap the Apple Pay button again. Note that `abort()` only works before the user authorizes payment — once they've authorized, use `fail()` in the `process` callback instead.

```javascript
const apple = evervault.ui.applePay(transaction, {
  requestShipping: true,
  onShippingAddressChange: async (address) => {
    const newCurrency = currencyForCountry(address.country);

    if (newCurrency !== transaction.details.currency) {
      await apple.abort();
      return { amount: 0, lineItems: [] };
    }

    return {
      amount: calculateTotal(address),
      lineItems: getLineItems(address),
    };
  },
  process: async (paymentMethod) => {
    // ...
  },
});

apple.on("cancel", () => {
  // Update checkout form currency/country and recreate the transaction if needed
});
```

> **Availability**
>
> There are several requirements that must be met for Apple Pay to be available
>   on the device. If you are having issues with the Apple Pay component not
>   rendering, please check the [Availability](#availability) section below to
>   ensure your device meets all the requirements.

### Process the payment

The `process` function is called when the user authorizes the payment. This is where you should finalize the payment with your payment processor. The encrypted payment method will be passed to the `process` function as the first argument. This should be sent to your backend which can then use [Relay](/relay) to safely send the decrypted payment method to any payment provider.

The full encrypted payment method object contains the following data:

```json
{
  "networkToken": {
    "number": "ev:Tk9D:hY5KJanIPOHBoI8S:AsnnjRl0FDe2zEddBAQG/eI2vN+b...:$",
    "expiry": {
      "month": "12",
      "year": "31"
    },
    "tokenServiceProvider": "Apple"
  },
  "card": {
    "brand": "visa",
    "lastFour": "1234",
    "displayName": "visa 1234",
    "paymentMethodType": "debit",
    "funding": "debit",
    "segment": "consumer",
    "country": "ie",
    "currency": "eur",
    "issuer": "Revolut Bank Uab"
  },
  "cryptogram": "ev:Tk9D:vUVeybXqrA9Ds4rZ...=:$",

  // The ECI value is optional with Apple Pay.
  // Learn more here: https://developer.apple.com/documentation/passkit/payment-token-format-reference#Detailed-payment-data-keys-3D-Secure
  "eci": "5",

  "paymentDataType": "3DSecure",
  "transactionType": "oneOff",

  "billingContact": {
    "familyName": "Doe",
    "givenName": "John",
    "phoneticFamilyName": null,
    "phoneticGivenName": null,
    "emailAddress": "john.doe@example.com",
    "phoneNumber": "1234567890",
    "address": {
      "addressLines": ["123 Main St", "Apt 4B"],
      "administrativeArea": "State",
      "country": "Country",
      "countryCode": "XX",
      "locality": "City",
      "postalCode": "12345",
      "subAdministrativeArea": "",
      "subLocality": ""
    }
  },
  "shippingContact": {
    "familyName": "Doe",
    "givenName": "John",
    "phoneticFamilyName": null,
    "phoneticGivenName": null,
    "emailAddress": "john.doe@example.com",
    "phoneNumber": "1234567890"
  }
}
```

The optional `card.paymentMethodType` field is one of `credit`, `debit`, `prepaid`, or `store`. It reflects the funding type of the **card the customer selected** in Apple Wallet (from the Payment Request API’s payment method). Prefer it over BIN-derived metadata such as `funding` when you need to know how the user intends to pay: for dual-network cards, BIN-based fields can still report `credit` even when the customer picked their debit card. If Apple does not provide a type, the field is omitted.

`paymentDataType` reflects the Apple token format from the credentials API (for example `3DSecure`). `transactionType` indicates the transaction category (`oneOff`, `recurring`, or `disbursement`) based on how you created the transaction. `billingContact` and `shippingContact` are only populated when the transaction requested those contact fields. `phoneticFamilyName`/`phoneticGivenName` are populated when the customer's Apple Wallet contact card includes a phonetic reading of their name (common in locales like Japan) — otherwise they're `null`.

## Use Apple Pay with your PSP

You can use Evervault's Apple Pay integration with any PSP. This means you:

- Don't use your PSP's Apple Pay integration.
- Use network tokens (provided by Evervault) with your PSP's APIs.

Evervault generates network tokens for Apple Pay transactions, not your PSP. After you have the network token, use it for all payments, retries, etc. with your PSP. There's no additional configuration (e.g., certificates) with your PSP or Apple needed. Most PSPs have network token APIs and parameters for passing network token data. Like other 3rd party API calls, use [Relay](/relay) to decrypt network token data and send it to your PSP.

## Availability

You can use the `availability` method to check if Apple Pay is available on the device. This method returns a promise that resolves to a string indicating the availability status.

- `available` - Apple Pay is available on the device.
- `unavailable` - Apple Pay is supported but not currently available on the device.
- `unsupported` - Apple Pay is not supported on the device.

```javascript
const apple = evervault.ui.applePay(transaction, { ...  })
const availability = await apple.availability();
console.log(availability);
// "available"
```

In order for Apple Pay to be available, the user's device or browser must meet the following requirements:

- The web page must be served over HTTPS.
- Have at least one card added to their Apple Wallet.
- The user must be using a compatible browser. Apple Pay is supported on Safari, Chrome, and Edge.
- If using Safari:
  - The user must have Apple Pay enabled in their browser settings. Settings > Advanced > Allow websites to check for Apple Pay and Apple card.
  - The user must have access to the biometric authentication controls on their device. If using a laptop this means the laptop must not be in clamshell mode and the user must have access to the Touch ID sensor.

## Customization

Apple Pay allows you to customize the appearance of the payment button with various predefined styles. These can be passed as additional options when initializing the Apple Pay component. You can see the available options in the [JS SDK documentation](/sdks/javascript#apple-pay).

```javascript
const apple = evervault.ui.applePay(transaction, {
  style: "black",
  borderRadius: 10,
  ...
});
```

## Configure card networks

Apple Pay allows you to specify the card networks that are supported by your merchant. This can be done by passing the `allowedCardNetworks` options when initializing the Apple Pay component. You can see the available options in the [Apple Pay docs](https://developer.apple.com/documentation/applepayontheweb/supported-networks). Please check with your payment processor to ensure that the card networks you specify are supported.

```javascript
const apple = evervault.ui.applePay(transaction, {
  allowedCardNetworks: ["visa", "mastercard"],
  ...
});
```

## Apple merchant identifier

By default, Evervault uses `merchant.com.evervault.{merchantId}` as the Apple Pay merchant identifier. This works with Evervault's domain verification and merchant-session API.

You can pass a custom `appleMerchantId` when initializing the component to match the iOS SDK surface:

```javascript
const apple = evervault.ui.applePay(transaction, {
  appleMerchantId: "merchant.com.example.store",
  process: async (paymentMethod) => {
    // ...
  },
});
```

A custom identifier is only used by the browser to open the Apple Pay sheet. It doesn't change merchant validation — that still uses Evervault's registered identifier unless the custom ID is separately registered with Apple for your domain.

## Transaction updates

Apple Pay allows you to update the transaction after a user has launched the Apple Pay modal. This can be done by leveraging the options described below.

### Responding to shipping address changes

You may want to alter the transaction amount based on the shipping address provided by the user. Apple Pay allows you to respond to changes in the shipping address after a user has launched the Apple Pay modal. This can be done by passing the `requestShipping` and `onShippingAddressChange` options when initializing the Apple Pay component. The `onShippingAddressChange` function should return an object with an updated `amount` and `lineItems` array.

```javascript
const apple = evervault.ui.applePay(transaction, {
  requestShipping: true,
  onShippingAddressChange: async (newAddress) => {
    const lineItems = getLineItems();
    const transactionAmount = calculateTransactionAmount(lineItems);

    const shippingAmount = await calculateShipping(newAddress.country);
    const shipping = {
      label: "Shipping",
      amount: shippingAmount,
    };
    return {
      amount: transactionAmount + shippingAmount,
      lineItems: [...lineItems, shipping],
    };
  },
});
```

### Responding to billing address changes

You can leverage the `requestBillingAddress` and `onPaymentMethodChange` options when initializing the Apple Pay component to respond to changes in the billing address.

```javascript
const apple = evervault.ui.applePay(transaction, {
  requestBillingAddress: true,
  onPaymentMethodChange: async (event) => {
    const lineItems = getLineItems(1);
    if (event.billingContact?.country === getCurrentCountry()) {
      lineItems.push({ label: "National tax", amount: 1000 });
    } else {
      lineItems.push({ label: "International tax", amount: 2000 });
    }
    const total = lineItems.reduce((acc, item) => acc + item.amount, 0);
    return {
      amount: total,
      lineItems,
    };
  },
});
```

> Due to limitations in the Apple Pay API, if also requesting a shipping
>   address, the `onPaymentMethodChange` event will not return the billing
>   address.

### Updating a transaction when Apple Pay is triggered

In some scenarios, you might want to perform an action before presenting the Apple Pay modal to the user, e.g., offering a discount code. You can do this by passing the `prepareTransaction` option when initializing the Apple Pay component. The `prepareTransaction` function should return a promise that resolves to an object with an updated `amount` and `lineItems` array.

```javascript
const apple = evervault.ui.applePay(transaction, {
  prepareTransaction: async () => {
    const updatedTransaction = await offerDiscount();
    return {
      amount: updatedTransaction.amount,
      lineItems: updatedTransaction.lineItems,
    };
  },
});
```

## Content security policy (CSP)

If you are using a Content Security Policy (CSP), you will need to add the following directives to allow the Evervault SDK to function correctly.

```
script-src https://js.evervault.com;
connect-src https://keys.evervault.com https://api.evervault.com;
frame-src https://ui-components.evervault.com;
```

## Notes

- The Apple Pay UI Component is currently not supported on devices in Mainland China.
- The Apple Pay UI Component requires a secure context (HTTPS) to function correctly.

#### Swift

### Register for an Apple Merchant ID

Before you can use Apple Pay for iOS with Evervault you need to obtain an Apple Merchant ID by [registering for a new identifier](https://developer.apple.com/help/account/capabilities/configure-apple-pay#create-a-merchant-identifier) on the Apple Developer portal. Fill out the description and identifier. We recommend you use the name of your app as the identifier e.g. `merchant.com.<YOUR_APPS_NAME>`

### Create a Payment Processing Certificate

Apple Pay needs to encrypt payment data such as card details. You will need a payment processing certificate for your app to allow Apple Pay to encrypt those details within your app.

In the Evervault dashboard, click the `Payments` tab at the top of the page. Then, on the left-hand side of the page click `Apple Pay` and at the bottom of the page under Certificates, click `Add certificate`. Follow the on screen instructions.

As part of this flow, Evervault will provide you with a certificate signing request that you must download.

Then, in a new tab, in the Apple Developer portal, under [Certificates](https://developer.apple.com/account/resources/certificates/add), create an Apple Pay Payment Processing Certificate, select the Merchant ID that you created in the previous step and click Continue. Under the Apple Pay Payment Processing Certificate section, click `Create Certificatea` and upload the certificate signing request you downloaded from the Evervault dashboard.

Download the Apple certificate you just created and go back to the Evervault dashboard and in the certificate set up dialog, upload the certificate you just downloaded from Apple.

### Setup Xcode

Once you have created your merchant identifier and payment processing certificate, you need to add the Apple Pay capability to your app in Xcode.

Open your project settings, click the `Signing & Capabilities` tab, and add the Apple Pay capability. You might be prompted to sign in to your developer account. Select the merchant ID you created earlier, and now your app is ready to accept Apple Pay.

### Install the Evervault SDK

The Evervault iOS SDK can be installed using the Swift Package Manager.

1. Open your Xcode project.
2. Navigate to **File** > **Swift Packages** > **Add Package Dependency**.
3. Enter the repository URL for the Evervault iOS SDK: `https://github.com/evervault/evervault-ios.git`.
4. Choose the latest available version or specify a version rule.
5. Click **Next** and follow the instructions to integrate the package into your project.

#### Initialize SDK

Now, let's initialize the SDK using our App and Team ID. If you don't have one yet, you can get one by creating an App in the [Evervault Dashboard](https://app.evervault.com).

```swift
import EvervaultCore

Evervault.shared.configure(teamId: "<TEAM_ID>", appId: "<APP_ID>")
```

If you need multiple instances of the Evervault SDK you can use the initializer as follows:

```swift
import EvervaultCore

let evervault = Evervault.init(teamId: "<TEAM_ID>", appId: "<APP_ID>")
```

### Create a Transaction

Next you will need to create a transaction to describe the payment you want to process. You will need to provide the country, currency, and line items for the transaction. The last item is the total for the transaction.

If the transaction is not constructed correctly e.g country or currency fields aren’t correct or there are no summary items then an `EvervaultError.InvalidTransaction` error will be thrown.

Please refer to [Apple's documentation](https://developer.apple.com/documentation/passkit/pkpaymentrequest/#Setting-currency-and-region-information) on requirements for country and currency and amount fields.

```swift
import EvervaultPayment

let oneOff = try! OneOffPaymentTransaction(
  country: "IE",
  currency: "EUR",
  paymentSummaryItems: [
    SummaryItem(label: "Mens Shirt", amount: Amount("30.00")),
    SummaryItem(label: "Socks", amount: Amount("5.00")),
    SummaryItem(label: "Total", amount: Amount("35.00"))
  ]
)

let transaction = EvervaultPayment.Transaction.oneOffPayment(oneOff)
```

`OneOffPaymentTransaction` and `RecurringPaymentTransaction` also accept a `requestPayerDetails` parameter to request billing contact fields — such as the payer's name, email, phone, or postal address — using PassKit's own `PKContactField` values:

```swift
import EvervaultPayment

let oneOff = try! OneOffPaymentTransaction(
  country: "IE",
  currency: "EUR",
  paymentSummaryItems: [
    SummaryItem(label: "Mens Shirt", amount: Amount("30.00")),
    SummaryItem(label: "Socks", amount: Amount("5.00")),
    SummaryItem(label: "Total", amount: Amount("35.00"))
  ],
  requestPayerDetails: [.name, .phoneticName, .phoneNumber, .emailAddress, .postalAddress]
)

let transaction = EvervaultPayment.Transaction.oneOffPayment(oneOff)
```

### Check if Apple Pay is available

Before displaying Apple Pay as a payment option, determine if the user’s device supports Apple Pay and that they have a card added to their wallet by calling the `isAvailable()` method.

```swift
let isAvailable = EvervaultPaymentViewRepresentable.isAvailable()
```

### Render the Apple Pay button

Next you can render the Apple Pay button. When you do this, you will need to pass in your Evervault App ID, your Apple Merchant Identifier, the transaction object, the card networks you support, any custom button styles, and a callback closure:

- `authorizedResponse`: Whenever the user successfully authorizes the payment, the decrypted ApplePayResponse (containing token, card info, cryptogram, etc.) will be written into your authorizedResponse variable. You can react to that state change however you like — navigate onward, show a confirmation screen, or send it off to your own backend to be sent via an Evervault Relay to your PSP. Refer to this section for the structure of the response.
- `onResult`: Use this callback to reset UI state or advance your checkout flow once the sheet closes. It's triggered whether the transaction succeeds or fails—for example, if Apple Pay is unavailable, the transaction is invalid, presentation fails, or Evervault cannot decrypt the payment. The callback returns a `Result<Void, EvervaultError>`. The `EvervaultError` includes a `localizedDescription` you can display in an alert, log for diagnostics, or present however appropriate.

```swift
struct ContentView: View {
  @State private var applePayResponse: ApplePayResponse? = nil
  let transaction = buildTransaction()

  var body: some View {
    EvervaultPaymentViewRepresentable(
      appId: "YOUR_EVERVAULT_APP_ID",
      appleMerchantId: "YOUR_APPLE_MERCHANT_IDENTIFIER",
      transaction: transaction,
      supportedNetworks: [.visa, .masterCard, .amex],
      authorizedResponse: $applePayResponse) { result in
          switch result {
          case .success(_):
              print("Payment sheet dismissed with success")
              if (applePayResponse != nil) {
                  // Send to PSP via Relay on your backend
              }
              break
          case let .failure(error):
              print("Payment error: \(error.localizedDescription)")
              break
          }
      }
  }
}
```

### Processing the Payment

If the payment is handled successfully, the Evervault encrypted payment method is available in `$applePayResponse` (in the example above). The `authorizedResponse` is an `ApplePayResponse` object containing the payment method details encrypted with the Evervault public key. You can send this encrypted payment method to your server and use Evervault Relay to decrypt the payment details when you send them to your PSP.

The ApplePayResponse object represented as JSON contains the following fields:

```json
{
  "networkToken": {
    "number": "ev:Tk9D:hY5KJanIPOHBoI8S:AsnnjRl0FDe2zEddBAQG/eI2vN+b...:$",
    "expiry": {
      "month": "12",
      "year": "31"
    },
    "tokenServiceProvider": "Apple"
  },
  "card": {
    "brand": "visa",
    "funding": "debit",
    "segment": "consumer",
    "country": "ie",
    "currency": "eur",
    "issuer": "Revolut Bank Uab"
  },
  "cryptogram": "ev:Tk9D:vUVeybXqrA9Ds4rZ...=:$",
  // The ECI value is optional with Apple Pay.
  // Learn more here: https://developer.apple.com/documentation/passkit/payment-token-format-reference#Detailed-payment-data-keys-3D-Secure
  "eci": "5",
  "paymentDataType": "3DSecure",
  "deviceManufacturerIdentifier": "string",
  "transactionType": "oneOff",

  // Only present if you requested the corresponding contact fields on the transaction
  "billingContact": {
    "givenName": "John",
    "familyName": "Doe",
    "phoneticGivenName": null,
    "phoneticFamilyName": null,
    "emailAddress": "john.doe@example.com",
    "phoneNumber": "1234567890",
    "postalAddress": {
      "street": "123 Main St",
      "city": "City",
      "state": "State",
      "postalCode": "12345",
      "country": "Country",
      "isoCountryCode": "XX"
    }
  },
  "shippingContact": {
    "givenName": "John",
    "familyName": "Doe",
    "phoneticGivenName": null,
    "phoneticFamilyName": null,
    "emailAddress": "john.doe@example.com",
    "phoneNumber": "1234567890"
  }
}
```

`transactionType` indicates the transaction category (`oneOff`, `recurring`, or `disbursement`) based on how you created the transaction. `billingContact` and `shippingContact` are only populated when the transaction requested those contact fields — otherwise they are omitted. `phoneticGivenName`/`phoneticFamilyName` are populated when the customer's Apple Wallet contact card includes a phonetic reading of their name (common in locales like Japan) — otherwise they're `null`.

## Customization

When initialising the `EvervaultPaymentViewRepresentable` you can pass two optional parameters — `buttonType` and `buttonStyle`. Please refer to the [Apple PassKit documentation](https://developer.apple.com/documentation/passkit/pkpaymentbutton#Configuring-the-appearance) on what preset button styles and types are available.

```swift
EvervaultPaymentViewRepresentable(
  // other fields...
  buttonStyle: .whiteOutline,
  buttonType: .checkout,
)
```

## Error Handling

All errors from creating the `Transaction` object and the errors surfaced in the `onResult` callback are of type `EvervaultError`.

- `InvalidTransactionError`: This error is thrown when there is an with the transaction. As a guideline to help prevent encountering this error:
  - `amount`: The format of this value depends on the `currency`. It follows ISO 4217 and depends on the minor unit of the currency e.g the number of decimal points for `USD` is 2, so the amount must be formatted as "50.00". This error will be thrown if you try to format the `amount` as "50.0". As another example, `JPY` has no minor unit so the `amount` must be formatted as "1000".
- `InvalidCurrencyError`: The currency is the three-letter ISO 4217 currency code that determines the currency the payment request uses. This error is thrown if the currency does not match this spec.
- `InvalidCountryError`: The country is the two-letter ISO 3166 country code. This error is thrown if the country does not match this spec.
- `EmptyTransactionError`: This error is thrown when a transaction has no summary items. The transaction must have at least 1 summary items, and the final item is the total.
- `ApplePayUnavailableError`: This error is thrown when Apple Pay is not available on the device.
- `ApplePayPaymentSheetError`: This error is thrown when an underlying error with the Apple Pay payment sheet occurs.
- `UnsupportedVersionError`: This error is thrown when trying to access a method that is not available on the current version of iOS.
- `ApplePayAuthorizationError`: This error is thrown when something goes wrong when authenticating with Apple Pay. The underlying error from Apple Pay is provided.
- `InternalError`: This error is thrown when something goes wrong during the handling of the payment data. An underlying reason will be provided in this case.

## Testing (sandbox)

In [Sandbox apps](/developers/sandbox), Apple Pay follows the same integration flow as production. The customer completes a real Apple Pay authorization in Apple Wallet, and Evervault decrypts the payment credentials from that token.

The Apple Pay sandbox environment allows merchants to test their implementation of Apple Pay with test credit and debit cards.

You’ll need the following to test Apple Pay in the sandbox:

- iPhone 6 or later, iPad mini 3 or later, iPad Air 2, iPad Pro, or Apple Watch
- App Store Connect sandbox tester account
- Supported test credentials

Follow the [Apple Pay sandbox guide](https://developer.apple.com/apple-pay/sandbox-testing/) from Apple for more information on how to set up a sandbox account and add test cards to your Apple Wallet.

This applies to both the [JavaScript SDK](/sdks/javascript#uiapplepay) (web) and [iOS SDK](/sdks/ios#apple-pay). No extra request fields are required — use the Apple Pay component as documented above.

> **Complete Apple Pay as normal**
>
> Sandbox no longer returns a fixed Visa test card for every authorization. The card brand returned depends on which card the user selects in their Apple Wallet during the Apple Pay payment flow.

### Test cards returned by brand

When the customer authorizes with a card of the given brand in their Apple Wallet, the encrypted `networkToken.number` you receive corresponds to:

| Number | Brand |
| --- | --- |
| **Supported brands** | |
| 4242 4242 4242 4242 | Visa |
| 5555 5555 5555 4444 | Mastercard |
| 3782 8224 6310 005 | American Express |
| 6011 1111 1111 1117 | Discover |

If the selected card brand is not Visa, Mastercard, American Express, or Discover, Evervault defaults to the Visa test card (`4242 4242 4242 4242`).

- [Network Tokens](/cards/network-tokens): Learn how to use Network Tokens to enhance your payment security.
- [Google Pay](/cards/google-pay): Learn how to integrate Google Pay into your app with Evervault.

