Apple Pay Integration via Iframe
Overview
The Apple Pay integration enables merchants to accept Apple Pay payments through Tranzila's iframe solution. The implementation is fully automated - merchants only need to include a script and create an iframe. All Apple Pay session management, token handling, and communication are handled transparently by Tranzila.
Prerequisites
Merchant Requirements
The following requirements must be met before implementation:
- Active credit card terminal with Tranzila, approved with an internet merchant number
- Apple Pay service purchased from Tranzila (paid service)
- Domain registration with Tranzila for Apple Pay service
- Valid SSL certificate (HTTPS required)
- Server access for verification file deployment
Technical Requirements
Supported Devices
- iPhone with Touch ID or Face ID
- iPad with Touch ID or Face ID
- Mac with Touch ID or authenticated via connected iPhone/iPad
Supported Browsers
On Mac:
- Safari - Full support
- Chrome - Supported (version 78+)
- Edge - Supported (version 79+)
- Firefox - Supported (version 119+)
- Opera - Supported
On iPhone/iPad:
- Safari - Full support
- Chrome - Supported
- Edge - Supported
- Firefox - Supported
- Other iOS browsers - Generally supported
Note: All browsers on iOS use Safari's WebKit engine, ensuring Apple Pay compatibility across all major browsers on Apple mobile devices.
For a complete list of supported devices, refer to Apple's device compatibility documentation.
Implementation Guide
If you are implementing hosted fields, you must also follow steps 1 and 2
Step 1: Domain Verification
Apple requires domain verification to enable Apple Pay. This process involves hosting a verification file on your domain.
1.1 Obtain Verification File
Download the verification file from Tranzila:
- URL:
https://api.tranzila.com/assets/apple_pay/merchant_authentication_file.zip - Extract the
.datfile from the archive - Preserve the original filename
1.2 Deploy Verification File
The verification file must be accessible at the following URL structure:
https://[your-domain]/.well-known/apple-developer-merchantid-domain-association
Deployment Requirements:
- The file must be served without a file extension
- The URL path is case-sensitive
- HTTPS protocol is mandatory
1.3 Framework-Specific Deployment
Static Hosting
Place the file in your public directory:
public/
└── .well-known/
└── apple-developer-merchantid-domain-association
React/Next.js/Remix
Place the file in the public directory:
public/
└── .well-known/
└── apple-developer-merchantid-domain-association
Vue.js
Place the file in the public directory:
public/
└── .well-known/
└── apple-developer-merchantid-domain-association
Angular
- Create the directory structure in your source folder:
src/
└── .well-known/
└── apple-developer-merchantid-domain-association
- Configure
angular.jsonto include the file in the build:
{
"projects": {
"your-app": {
"architect": {
"build": {
"options": {
"assets": [
"src/favicon.ico",
"src/assets",
{
"glob": "apple-developer-merchantid-domain-association",
"input": "src/.well-known/",
"output": ".well-known/"
}
]
}
}
}
}
}
}
Express/Node.js
Configure static file serving:
app.use('/.well-known', express.static('.well-known'));
1.4 Verify Deployment
Confirm file accessibility using the following command:
curl https://[your-domain]/.well-known/apple-developer-merchantid-domain-association
Expected response: The contents of the verification file
1.5 Complete Registration
Important: After successful file deployment, you must contact Tranzila support to complete the Apple Pay activation and domain registration for your terminal. The service will not work until Tranzila confirms the registration.
Contact support at: 073-222-4444
Step 2: Include Required Scripts
Add jQuery and the Tranzila Apple Pay script to your page. jQuery is required as a dependency for the Tranzila Apple Pay script to function properly.
Standard Implementation
<script type="text/javascript" src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script>document.write('<script src="https://directng.tranzila.com/assets/js/tranzilanapple_v3.js?v=' + Date.now() + '"><\/script>');</script>
<script>var $n = jQuery.noConflict(true);</script>
Alternative Dynamic Loading Implementation with Error Handling
For modern JavaScript applications with proper error handling:
// Load jQuery first with error handling
const jqueryScript = document.createElement('script');
jqueryScript.src = 'https://code.jquery.com/jquery-3.6.0.js';
jqueryScript.async = true;
document.head.appendChild(jqueryScript);
jqueryScript.onload = function() {
console.log('jQuery loaded successfully');
// Load Tranzila Apple Pay script after jQuery loads
const tranzilaScript = document.createElement('script');
tranzilaScript.src = 'https://directng.tranzila.com/assets/js/tranzilanapple_v3.js?v=' + Date.now();
tranzilaScript.async = true;
document.head.appendChild(tranzilaScript);
tranzilaScript.onload = function() {
console.log('Tranzila Apple Pay script loaded successfully');
// Set jQuery noConflict mode
if (window.jQuery) {
window.$n = jQuery.noConflict(true);
}
};
tranzilaScript.onerror = function() {
console.error('Failed to load Tranzila Apple Pay script');
// Handle error - perhaps show a message to the user
};
};
jqueryScript.onerror = function() {
console.error('Failed to load jQuery');
// Handle error - perhaps show a message to the user
};
Notes:
- jQuery is required for the Tranzila Apple Pay script to function
- The
noConflictmode prevents conflicts with existing jQuery instances - The timestamp parameter ensures the latest version is loaded
- The scripts must be included on the same page that contains the payment iframe
- Use the standard implementation for simple HTML pages
- Use the dynamic loading approach for SPAs or when scripts need to be loaded conditionally
Step 3: Create Payment Iframe
Configure the iframe with Apple Pay enabled. When Apple Pay is available on the user's device, it will automatically appear as a payment option within the iframe.
Option 1: GET Method (URL Parameters)
<iframe
src="https://direct.tranzila.com/[terminal-name]/iframenew.php?sum=100¤cy=1&apple_pay=1&lang=en"
width="100%"
height="600"
frameborder="0"
allowpaymentrequest="true">
</iframe>
Option 2: POST Method (Form Submission)
<form id="payment-form"
action="https://direct.tranzila.com/[terminal-name]/iframenew.php"
method="POST"
target="payment-iframe">
<!-- Required Parameters -->
<input type="hidden" name="sum" value="100">
<input type="hidden" name="currency" value="1">
<input type="hidden" name="apple_pay" value="1">
<!-- Response URLs -->
<input type="hidden" name="success_url_address" value="https://your-domain.com/success">
<input type="hidden" name="fail_url_address" value="https://your-domain.com/failure">
<!-- Optional Parameters -->
<input type="hidden" name="lang" value="en">
<input type="hidden" name="contact" value="customer@email.com">
<input type="hidden" name="company" value="Customer Name">
<input type="hidden" name="pdesc" value="Product Description">
</form>
<iframe name="payment-iframe"
width="100%"
height="600"
frameborder="0"
allowpaymentrequest="true">
</iframe>
<script>
// Submit form to load iframe
document.getElementById('payment-form').submit();
</script>
Complete Implementation Examples
HTML Implementation
Using GET Method
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Checkout - Apple Pay Enabled</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.checkout-container {
max-width: 600px;
margin: 0 auto;
background: white;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 30px;
}
h1 {
color: #333;
margin-bottom: 30px;
}
.payment-iframe {
width: 100%;
height: 600px;
border: none;
border-radius: 8px;
}
</style>
</head>
<body>
<div class="checkout-container">
<h1>Complete Your Payment</h1>
<!-- Required Scripts for Apple Pay -->
<script type="text/javascript" src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script>document.write('<script src="https://directng.tranzila.com/assets/js/tranzilanapple_v3.js?v=' + Date.now() + '"><\/script>');</script>
<script>var $n = jQuery.noConflict(true);</script>
<!-- Payment Iframe with Apple Pay Enabled -->
<iframe
class="payment-iframe"
src="https://direct.tranzila.com/[terminal-name]/iframenew.php?sum=100¤cy=1&apple_pay=1&lang=en&success_url_address=https://your-domain.com/success&fail_url_address=https://your-domain.com/failure"
allowpaymentrequest="true">
</iframe>
</div>
</body>
</html>
Using POST Method
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Checkout - Apple Pay with POST</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.checkout-container {
max-width: 600px;
margin: 0 auto;
background: white;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 30px;
}
h1 {
color: #333;
margin-bottom: 30px;
}
.payment-iframe {
width: 100%;
height: 600px;
border: none;
border-radius: 8px;
}
</style>
</head>
<body>
<div class="checkout-container">
<h1>Complete Your Payment</h1>
<!-- Required Scripts for Apple Pay -->
<script type="text/javascript" src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script>document.write('<script src="https://directng.tranzila.com/assets/js/tranzilanapple_v3.js?v=' + Date.now() + '"><\/script>');</script>
<script>var $n = jQuery.noConflict(true);</script>
<!-- POST Form for Iframe -->
<form id="payment-form"
action="https://direct.tranzila.com/[terminal-name]/iframenew.php"
method="POST"
target="payment-iframe">
<!-- Required Parameters -->
<input type="hidden" name="sum" value="100">
<input type="hidden" name="currency" value="1">
<input type="hidden" name="apple_pay" value="1">
<!-- Response URLs -->
<input type="hidden" name="success_url_address" value="https://your-domain.com/success">
<input type="hidden" name="fail_url_address" value="https://your-domain.com/failure">
<!-- Optional Parameters -->
<input type="hidden" name="lang" value="en">
<input type="hidden" name="contact" value="customer@email.com">
<input type="hidden" name="company" value="John Doe">
<input type="hidden" name="pdesc" value="Premium Package">
</form>
<!-- Payment Iframe -->
<iframe name="payment-iframe"
class="payment-iframe"
allowpaymentrequest="true">
</iframe>
<script>
// Submit form when page loads
window.onload = function() {
document.getElementById('payment-form').submit();
};
</script>
</div>
</body>
</html>
React Implementation
Using GET Method
// PaymentPage.jsx
import React, { useEffect } from 'react';
const PaymentPage = () => {
// Configuration
const TERMINAL_NAME = 'your-terminal';
const AMOUNT = '100';
const CURRENCY = '1'; // 1=ILS, 2=USD, 978=EUR
useEffect(() => {
// Load jQuery
const jquery = document.createElement('script');
jquery.src = 'https://code.jquery.com/jquery-3.6.0.js';
jquery.async = true;
document.body.appendChild(jquery);
jquery.onload = () => {
// Load Tranzila Apple Pay script after jQuery
const script = document.createElement('script');
script.innerHTML = `document.write('<script src="https://directng.tranzila.com/assets/js/tranzilanapple_v3.js?v=' + Date.now() + '"><\\/script>');`;
document.body.appendChild(script);
// Set jQuery noConflict
const noConflict = document.createElement('script');
noConflict.innerHTML = 'var $n = jQuery.noConflict(true);';
document.body.appendChild(noConflict);
};
// Cleanup
return () => {
const scripts = document.querySelectorAll('script[src*="jquery"], script[src*="tranzilanapple"]');
scripts.forEach(script => script.remove());
};
}, []);
// Build iframe URL with parameters
const iframeUrl = `https://direct.tranzila.com/${TERMINAL_NAME}/iframenew.php?` +
new URLSearchParams({
sum: AMOUNT,
currency: CURRENCY,
apple_pay: '1',
lang: 'en',
success_url_address: window.location.origin + '/success',
fail_url_address: window.location.origin + '/failure'
}).toString();
return (
<div className="payment-container">
<h1>Complete Your Payment</h1>
<iframe
src={iframeUrl}
width="100%"
height="600"
frameBorder="0"
allowPaymentRequest={true}
title="Payment Form"
/>
</div>
);
};
export default PaymentPage;
Using POST Method
// PaymentPagePost.jsx
import React, { useEffect, useRef } from 'react';
const PaymentPagePost = () => {
const formRef = useRef(null);
// Configuration
const TERMINAL_NAME = 'your-terminal';
const paymentData = {
sum: '100',
currency: '1', // 1=ILS, 2=USD, 978=EUR
apple_pay: '1',
lang: 'en',
success_url_address: window.location.origin + '/success',
fail_url_address: window.location.origin + '/failure',
contact: 'customer@example.com',
company: 'John Doe',
pdesc: 'Premium Package'
};
useEffect(() => {
// Load jQuery
const jquery = document.createElement('script');
jquery.src = 'https://code.jquery.com/jquery-3.6.0.js';
jquery.async = true;
document.body.appendChild(jquery);
jquery.onload = () => {
// Load Tranzila Apple Pay script after jQuery
const script = document.createElement('script');
script.innerHTML = `document.write('<script src="https://directng.tranzila.com/assets/js/tranzilanapple_v3.js?v=' + Date.now() + '"><\\/script>');`;
document.body.appendChild(script);
// Set jQuery noConflict
const noConflict = document.createElement('script');
noConflict.innerHTML = 'var $n = jQuery.noConflict(true);';
document.body.appendChild(noConflict);
// Submit form after scripts load
setTimeout(() => {
if (formRef.current) {
formRef.current.submit();
}
}, 100);
};
// Cleanup
return () => {
const scripts = document.querySelectorAll('script[src*="jquery"], script[src*="tranzilanapple"]');
scripts.forEach(script => script.remove());
};
}, []);
return (
<div className="payment-container">
<h1>Complete Your Payment</h1>
<form
ref={formRef}
action={`https://direct.tranzila.com/${TERMINAL_NAME}/iframenew.php`}
method="POST"
target="payment-iframe"
style={{ display: 'none' }}>
{Object.entries(paymentData).map(([key, value]) => (
<input key={key} type="hidden" name={key} value={value} />
))}
</form>
<iframe
name="payment-iframe"
width="100%"
height="600"
frameBorder="0"
allowPaymentRequest={true}
title="Payment Form"
/>
</div>
);
};
export default PaymentPagePost;
// App.jsx - Complete React Application Example
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import PaymentPage from './PaymentPage';
import SuccessPage from './SuccessPage';
import FailurePage from './FailurePage';
function App() {
return (
<Router>
<Routes>
<Route path="/checkout" element={<PaymentPage />} />
<Route path="/success" element={<SuccessPage />} />
<Route path="/failure" element={<FailurePage />} />
</Routes>
</Router>
);
}
export default App;
/* PaymentPage.css */
.payment-container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
background: white;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.payment-container h1 {
color: #333;
margin-bottom: 30px;
font-size: 24px;
}
.payment-container iframe {
border: none;
border-radius: 8px;
}
Angular Implementation
Using GET Method
// payment.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
@Component({
selector: 'app-payment',
templateUrl: './payment.component.html',
styleUrls: ['./payment.component.css']
})
export class PaymentComponent implements OnInit, OnDestroy {
iframeUrl: SafeResourceUrl;
// Configuration
private readonly TERMINAL_NAME = 'your-terminal';
private readonly AMOUNT = '100';
private readonly CURRENCY = '1'; // 1=ILS, 2=USD, 978=EUR
constructor(private sanitizer: DomSanitizer) {
// Build iframe URL
const params = new URLSearchParams({
sum: this.AMOUNT,
currency: this.CURRENCY,
apple_pay: '1',
lang: 'en',
success_url_address: window.location.origin + '/success',
fail_url_address: window.location.origin + '/failure'
});
const url = `https://direct.tranzila.com/${this.TERMINAL_NAME}/iframenew.php?${params}`;
this.iframeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(url);
}
ngOnInit(): void {
// Load jQuery
this.loadScript('https://code.jquery.com/jquery-3.6.0.js', () => {
// Load Tranzila Apple Pay script after jQuery
const script = document.createElement('script');
script.innerHTML = `document.write('<script src="https://directng.tranzila.com/assets/js/tranzilanapple_v3.js?v=' + Date.now() + '"><\\/script>');`;
document.body.appendChild(script);
// Set jQuery noConflict
const noConflict = document.createElement('script');
noConflict.innerHTML = 'var $n = jQuery.noConflict(true);';
document.body.appendChild(noConflict);
});
}
ngOnDestroy(): void {
// Remove scripts on component destroy
const scripts = document.querySelectorAll('script[src*="jquery"], script[src*="tranzilanapple"]');
scripts.forEach(script => script.remove());
}
private loadScript(src: string, callback?: () => void): void {
const script = document.createElement('script');
script.src = src;
script.async = true;
if (callback) {
script.onload = callback;
}
document.body.appendChild(script);
}
}
Using POST Method
// payment-post.component.ts
import { Component, OnInit, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
@Component({
selector: 'app-payment-post',
template: `
<div class="payment-container">
<h1>Complete Your Payment</h1>
<form #paymentForm
[action]="formAction"
method="POST"
target="payment-iframe"
style="display: none">
<input type="hidden" name="sum" [value]="paymentData.sum">
<input type="hidden" name="currency" [value]="paymentData.currency">
<input type="hidden" name="apple_pay" value="1">
<input type="hidden" name="lang" [value]="paymentData.lang">
<input type="hidden" name="success_url_address" [value]="paymentData.success_url_address">
<input type="hidden" name="fail_url_address" [value]="paymentData.fail_url_address">
<input type="hidden" name="contact" [value]="paymentData.contact">
<input type="hidden" name="company" [value]="paymentData.company">
<input type="hidden" name="pdesc" [value]="paymentData.pdesc">
</form>
<iframe name="payment-iframe"
width="100%"
height="600"
frameborder="0"
allowpaymentrequest="true"
title="Payment Form">
</iframe>
</div>
`,
styleUrls: ['./payment.component.css']
})
export class PaymentPostComponent implements OnInit, AfterViewInit {
@ViewChild('paymentForm') paymentForm!: ElementRef<HTMLFormElement>;
// Configuration
private readonly TERMINAL_NAME = 'your-terminal';
formAction: string;
paymentData = {
sum: '100',
currency: '1', // 1=ILS, 2=USD, 978=EUR
lang: 'en',
success_url_address: window.location.origin + '/success',
fail_url_address: window.location.origin + '/failure',
contact: 'customer@example.com',
company: 'John Doe',
pdesc: 'Premium Package'
};
constructor(private sanitizer: DomSanitizer) {
this.formAction = `https://direct.tranzila.com/${this.TERMINAL_NAME}/iframenew.php`;
}
ngOnInit(): void {
// Load jQuery
this.loadScript('https://code.jquery.com/jquery-3.6.0.js', () => {
// Load Tranzila Apple Pay script after jQuery
const script = document.createElement('script');
script.innerHTML = `document.write('<script src="https://directng.tranzila.com/assets/js/tranzilanapple_v3.js?v=' + Date.now() + '"><\\/script>');`;
document.body.appendChild(script);
// Set jQuery noConflict
const noConflict = document.createElement('script');
noConflict.innerHTML = 'var $n = jQuery.noConflict(true);';
document.body.appendChild(noConflict);
});
}
ngAfterViewInit(): void {
// Submit form after view initialization
setTimeout(() => {
if (this.paymentForm && this.paymentForm.nativeElement) {
this.paymentForm.nativeElement.submit();
}
}, 500);
}
private loadScript(src: string, callback?: () => void): void {
const script = document.createElement('script');
script.src = src;
script.async = true;
if (callback) {
script.onload = callback;
}
document.body.appendChild(script);
}
}
<!-- payment.component.html -->
<div class="payment-container">
<h1>Complete Your Payment</h1>
<iframe
[src]="iframeUrl"
width="100%"
height="600"
frameborder="0"
allowpaymentrequest="true"
title="Payment Form">
</iframe>
</div>
/* payment.component.css */
.payment-container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
background: white;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.payment-container h1 {
color: #333;
margin-bottom: 30px;
font-size: 24px;
}
.payment-container iframe {
border: none;
border-radius: 8px;
}
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { PaymentComponent } from './payment/payment.component';
import { SuccessComponent } from './success/success.component';
import { FailureComponent } from './failure/failure.component';
const routes: Routes = [
{ path: 'checkout', component: PaymentComponent },
{ path: 'success', component: SuccessComponent },
{ path: 'failure', component: FailureComponent },
{ path: '', redirectTo: '/checkout', pathMatch: 'full' }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { PaymentComponent } from './payment/payment.component';
import { SuccessComponent } from './success/success.component';
import { FailureComponent } from './failure/failure.component';
@NgModule({
declarations: [
AppComponent,
PaymentComponent,
SuccessComponent,
FailureComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Security and Compliance
PCI-DSS Compliance
The iframe implementation maintains full PCI-DSS compliance:
- Credit card details are never processed on your domain
- All sensitive data is handled securely within Tranzila's certified environment
- Your website does not need PCI-DSS certification when using the iframe solution
SSL Certificate Requirements
- Type: Valid SSL certificate (DV, OV, or EV)
- Validation: Certificate must be properly installed and configured
- Protocol: HTTPS is mandatory for both the parent page and domain verification
Testing
Production-Only Testing
Important: There is no sandbox or testing environment for Apple Pay integration. All testing must be performed in production after completing the integration.
Testing guidelines:
- Complete all implementation steps including domain verification
- Ensure Tranzila support has confirmed your domain registration
- Test with small amounts initially
- Verify successful transactions in your Tranzila dashboard
API Reference
Iframe Parameters
The following table lists the essential parameters for Apple Pay integration. For a complete list of all available iframe parameters, refer to the full iframe parameters documentation.
| Parameter | Type | Required | Description |
|---|---|---|---|
sum | decimal | Yes | Transaction amount |
currency | integer | Yes | Currency code: 1=ILS, 2=USD, 978=EUR |
apple_pay | integer | Yes | Enable Apple Pay: 1=enabled |
lang | string | No | Interface language: il=Hebrew, us=English |
success_url_address | string | Yes | Redirect URL for successful transactions |
fail_url_address | string | Yes | Redirect URL for failed transactions |
contact | string | No | Customer email address |
company | string | No | Customer name |
pdesc | string | No | Product or service description |
tranmode | string | No | Transaction mode: A=Standard, V=Verification |
How It Works
- Automatic Detection: The Tranzila iframe automatically detects if Apple Pay is available on the user's device
- Button Display: If available, an Apple Pay button appears within the payment form inside the iframe
- User Interaction: The customer clicks the Apple Pay button and authenticates the payment on their device
- Session Management: The Tranzila script automatically handles the entire Apple Pay session
- Token Processing: Payment tokens are automatically processed without any merchant intervention
- Transaction Completion: After successful payment, users are redirected to success URL; on failure, to failure URL
- Notification: A server-side notification (NOTIFY) is also sent to your configured endpoint
Note: The payment process is initiated only when the customer clicks the Apple Pay button within the iframe. The parent page simply waits for the redirect after transaction completion.
Troubleshooting
Domain Verification Issues
Symptom
Apple Pay option does not appear in the iframe despite proper implementation.
Resolution
- Verify file accessibility:
curl -I https://your-domain.com/.well-known/apple-developer-merchantid-domain-association
Expected response: HTTP 200 OK
- Confirm HTTPS configuration:
openssl s_client -connect your-domain.com:443 -servername your-domain.com
- Validate file is served without extension and with correct MIME type:
- Apache
.htaccess:
<Files "apple-developer-merchantid-domain-association">
ForceType application/octet-stream
</Files>
- Nginx configuration:
location = /.well-known/apple-developer-merchantid-domain-association {
default_type application/octet-stream;
}
- Contact Tranzila support to confirm domain registration completion
Script Loading Issues
Symptom
Console errors related to script loading.
Resolution
- Verify the script URL is accessible:
curl -I https://directng.tranzila.com/assets/js/tranzilanapple_v3.js
- Ensure no Content Security Policy blocks the script:
<meta http-equiv="Content-Security-Policy"
content="script-src 'self' https://direct.tranzila.com;">
- Confirm the script is loaded before the iframe:
// Ensure script loads first
const script = document.createElement('script');
script.src = 'https://directng.tranzila.com/assets/js/tranzilanapple_v3.js';
script.onload = () => {
// Now safe to create iframe
createPaymentIframe();
};
document.body.appendChild(script);
Apple Pay Not Appearing
Symptom
Apple Pay button does not appear in the iframe on supported devices.
Possible Causes and Solutions
- Browser Compatibility: Ensure using a supported browser (Safari, Chrome 78+, Edge 79+, Firefox 119+, Opera)
- Missing apple_pay Parameter: Ensure
apple_pay=1is included in iframe URL - Terminal Not Configured: Contact Tranzila to verify Apple Pay is enabled for your terminal
- Device Not Supported: Verify device has Touch ID/Face ID capability
- No Cards in Wallet: User must have at least one card added to Apple Wallet
CORS or Security Errors
Symptom
Browser console shows CORS or security-related errors.
Resolution
Ensure the iframe includes the allowpaymentrequest attribute:
<iframe allowpaymentrequest="true" ...>
Important Notes
Security Considerations
- HTTPS Required: Both your domain and the page containing the iframe must use HTTPS
- Domain Verification: The verification file must remain accessible at all times
- No Additional Code: Do not attempt to manipulate or communicate with the iframe - all handling is automatic
Browser Compatibility
Apple Pay through iframe is supported on:
Mac:
- Safari (all versions with Apple Pay support)
- Chrome (version 78+)
- Edge (version 79+)
- Firefox (version 119+)
- Opera
iOS devices (iPhone/iPad):
- Safari
- Chrome
- Edge
- Firefox
- All other major browsers (all iOS browsers use WebKit engine)
Transaction Processing
- Apple Pay transactions appear in Tranzila dashboard like regular credit card transactions
- The last 4 digits shown are the Device Account Number, not the actual card number
- Apple Pay tokens can be used for refunds (credits) and transaction cancellations, but cannot be used for new recurring payments
- Supported Transaction Modes: Apple Pay only supports transaction modes A (Standard Transaction) and V (Verification/J5). Other transaction types such as pre-authorization or token creation are not supported
API Charging After J5 Verification
If you performed a J5 verification (tranmode=V) through Apple Pay in the iframe, you can charge the transaction later via API:
Step 1: J5 Verification (Done via iframe with Apple Pay)
The verification reserves the credit limit and returns:
- Transaction ID
- Authorization number
- Token
Step 2: Force Charge via API
To obtain API credentials, contact Tranzila support at 073-222-4444.
For complete authentication documentation, see Tranzila API Authentication Guide.
POST https://api.tranzila.com/v1/transaction/credit_card/create
Headers:
Content-Type: application/json
X-tranzila-api-app-key: [your-app-key]
X-tranzila-api-request-time: [unix-timestamp]
X-tranzila-api-nonce: [40-byte-nonce]
X-tranzila-api-access-token: [hmac-hash]
Body:
{
"terminal_name": "your-terminal",
"txn_currency_code": "ILS",
"txn_type": "force",
"reference_txn_id": 148, // Transaction ID from J5 verification
"authorization_number": "0000393", // Auth number from J5 verification
"card_number": "token-from-verification", // Token received from verification
"expire_month": 3,
"expire_year": 24,
"payment_plan": 1,
"items": [
{
"name": "Product",
"unit_price": 100,
"type": "I",
"units_number": 1,
"unit_type": 1,
"price_type": "G",
"currency_code": "ILS"
}
]
}
Important: The force charge (J4) must include:
reference_txn_id: The transaction ID from the J5 verificationauthorization_number: The authorization number from the J5 verificationcard_number: The token received from the verification
For complete API documentation, see Tranzila API Documentation
Support
For technical assistance, contact Tranzila support:
- Phone: 073-222-4444
- Email: support@interspace.net
- Dashboard: https://my.tranzila.com
Documentation Version: 3.0 | Last Updated: January 2026