PayFacto API - V2.0 - Digital Wallets : Apple Pay™ - Online Checkout
PayFacto API - V2.0 - Digital Wallets : Apple Pay™ - Online Checkout
InApp
Integrate Apple Pay into your iOS application and process payments through the PayFacto Payment API v2.0. There are two implementation methods depending on who decrypts the Apple Pay token — your server or PayFacto.
Choose an Integration Method
Your server decrypts the Apple Pay token and extracts the raw card data (DPAN, expiry, cryptogram). You then send the decrypted fields to PayFacto for processing.
✅ Full control over decryption
✅ You own the key management
⚠️ Requires ECDH + AES-256-GCM implementation
Apple Pay: use PayFacto payment processing certificate for signing
Your server forwards the raw encrypted Apple Pay token to PayFacto. PayFacto handles decryption on its end using the PayFacto payment processing certificate.
✅ Simpler — no decryption required
✅ Pass the token as-is
⚠️ PayFacto payment processing certificate must be used
Use PayFacto certificate during token generation
A
Method A — Partner DecryptsYour server performs ECDH decryption
A1
Decrypt the Apple Pay Token
⚠️
Always verify the Apple Pay token signature before decrypting. This confirms the token genuinely came from Apple and prevents forgery.
Follow these three steps on your server to produce the plaintext payment data:
1
Verify the token signature (strongly recommended)
Use Apple's root certificates to validate the token signature chain. Confirm the token truly came from Apple Pay. This step is not strictly required to perform decryption, but is required for security compliance and to prevent replay attacks.
2
Derive the symmetric AES key
Combine your merchant private key with the token's ephemeralPublicKey using ECDH (Elliptic Curve Diffie-Hellman) to produce a shared secret. Run that shared secret through Apple's KDF (key derivation function) using SHA-256 to produce the AES-256-GCM symmetric key.
3
Decrypt the payment data
Use AES-256-GCM with the derived key and the IV defined in Apple's specification. The authentication tag is embedded in the data field. If authentication fails, discard the token immediately. A successful decryption produces a plaintext JSON payload.
JSON — Decrypted Apple Pay payload
{
"applicationPrimaryAccountNumber": "489537XXXXXX1234",
"applicationExpirationDate": "3010",
"currencyCode": "840",
"transactionAmount": 1999,
"deviceManufacturerIdentifier": "123456789012",
"paymentDataType": "3DSecure",
"paymentData": {
"onlinePaymentCryptogram": "Qk9xR3ZpS2p0aE1UeFJ5c0RkPQ==",
"eciIndicator": "05"
}
}Fields to extract from the decrypted payload
| Decrypted field | Maps to | Notes |
|---|
| applicationPrimaryAccountNumber | Card number (DPAN) | Pass as card.number in the charge request. This is the Device Primary Account Number, not the physical card number. |
| applicationExpirationDate | Expiry date | Format from Apple is YYMM. Remap to expiry.month (MM) and expiry.year (20YY) before sending to PayFacto. |
| paymentData.onlinePaymentCryptogram | Cryptogram | Base64-encoded. Must be converted to HEX before sending to PayFacto. See Step A2 below. |
| paymentData.eciIndicator | ECI indicator | Pass as card.authentication.wallet.eciIndicator. |
ℹ️
Apple Pay returns the expiry date in YYMM format (e.g. 3010 = October 2030). PayFacto expects expiry.month (MM) and expiry.year (YYYY) as separate fields. Split and reformat before building the charge request.
| Apple Pay field | Apple format | PayFacto field | PayFacto format |
|---|
| applicationExpirationDate | 3010 → YYMM | card.expiry.month | 10 (MM) |
| applicationExpirationDate | 3010 → YYMM | card.expiry.year | 2030 (YYYY — prepend 20) |
A3
Convert the Cryptogram from Base64 to HEX
⚠️
The cryptogram returned by Apple Pay is Base64-encoded. PayFacto requires it in hexadecimal (HEX) format. Convert it before building the charge request.
| Encoding | Example value |
|---|
| Base64 (from Apple Pay) | Qk9xR3ZpS2p0aE1UeFJ5c0RkPQ== |
| HEX (send to PayFacto) | 424F714776694B6A74684D547852797344643D |
Java — Base64 → HEX conversion
import java.util.HexFormat;
public static String getCryptogramHexString(final ApplePayPaymentPlainData plainData) {
final String base64String = plainData.getPaymentData().getOnlinePaymentCryptogram();
final byte[] bytes = decodeBase64(base64String);
return HexFormat.of().formatHex(bytes);
}
A4
Build and Submit the Charge
ℹ️
Use paymentMethod.type: "CARD" with a card.authentication.wallet block. Set wallet.type to APPLE_PAY and pass the HEX-encoded cryptogram.
Charge request body — Method A
| Field | Constraint | Description |
|---|
| amount | integer · required | Amount in cents. Example: 5000 = $50.00 |
| invoiceNumber | string · required | Merchant invoice reference. Max 25 chars. |
| capture | boolean · optional | Default: true. Set false for pre-authorization. |
| paymentMethod.type | string · required | CARD |
| paymentMethod.card.number | string · required | DPAN extracted from the decrypted Apple Pay payload (applicationPrimaryAccountNumber). |
| paymentMethod.card.expiry.month | string · required | Expiry month (MM) remapped from Apple's YYMM format. |
| paymentMethod.card.expiry.year | string · required | Expiry year (YYYY) remapped from Apple's YYMM format. |
| paymentMethod.card.authentication.wallet.type | string · required | APPLE_PAY |
| paymentMethod.card.authentication.wallet.eciIndicator | string · required | ECI indicator from the decrypted payload (paymentData.eciIndicator). |
| paymentMethod.card.authentication.wallet.cryptogram | string · required | Cryptogram converted to HEX (from paymentData.onlinePaymentCryptogram). Do not send raw Base64. |
JSON — POST /charges body (Method A — Partner Decrypts)
{
"amount": "5000",
"invoiceNumber": "123456789012",
"capture": true,
"paymentMethod": {
"type": "CARD",
"card": {
"number": "489537XXXXXX1234",
"expiry": {
"month": "10",
"year": "2030"
},
"authentication": {
"wallet": {
"eciIndicator": "05",
"type": "APPLE_PAY",
"cryptogram": "424F714776694B6A74684D547852797344643D"
}
}
}
}
}B
Method B — PayFacto DecryptsPayFacto certificate used during token generation
B1
Use the PayFacto Payment Processing Certificate
ℹ️
During Apple Pay token generation on the device, the PayFacto payment processing certificate must be used as the encryption certificate. This allows PayFacto to decrypt the token on its end. Contact PayFacto to obtain the certificate.
🔒
PayFacto Payment Processing Certificate
This certificate replaces your own merchant certificate for Apple Pay token encryption. The token generated by Apple Pay is encrypted with PayFacto's public key, so only PayFacto can decrypt it. Contact your PayFacto integration team to obtain and configure this certificate in your Apple Pay setup.
B2
Receive and Forward the Token
ℹ️
With the PayFacto certificate in place, your server receives the encrypted Apple Pay token from the device. Pass the entire token JSON string exactly as received as the paymentData field. No decryption, field extraction, or cryptogram conversion is needed.
⚠️
Pass the token value exactly as received — as a JSON string. Do not parse, modify, or re-serialize it. PayFacto will handle all decryption internally.
B3
Build and Submit the Charge
ℹ️
Use paymentMethod.type: "CARD" with a card.authentication.wallet block. Set wallet.type to APPLE_PAY and pass the raw token JSON string as wallet.paymentData. No card number, expiry, ECI, or cryptogram fields are required.
Charge request body — Method B
| Field | Constraint | Description |
|---|
| amount | integer · required | Amount in cents. |
| invoiceNumber | string · required | Merchant invoice reference. Max 25 chars. |
| capture | boolean · optional | Default: true. Set false for pre-authorization. |
| paymentMethod.type | string · required | CARD |
| paymentMethod.card.authentication.wallet.type | string · required | APPLE_PAY |
| paymentMethod.card.authentication.wallet.paymentData | string · required | The complete Apple Pay token JSON string as received from the device. Pass as-is — do not parse or modify. |
JSON — POST /charges body (Method B — PayFacto Decrypts)
"paymentMethod": {
"type": "CARD",
"card": {
"authentication": {
"wallet": {
"type": "APPLE_PAY",
"paymentData": "{\"data\":\"19T\/dTGGl3kxsA5vYwratId7Six3l...\",...}"
}
}
}
}