Altima Pay — Payment Gateway User Manual

Version 2.0 Multi-Tenant Architecture Merchant Warrior Integration

Setup Summary

Choose the configuration that matches your deployment scenario. Each setup type has a concise checklist to get you operational quickly.

Scenario A

Self-Hosted — Single Tenant

Your organisation deploys its own instance with custom branding on a private domain.

  1. Clone or download the repository.
  2. Set VITE_TENANT_ID=your-organisation in your environment.
  3. Add your Merchant Warrior credentials:
    VITE_YOUR_MW_MERCHANT_UUID
    VITE_YOUR_MW_API_KEY
    VITE_YOUR_MW_PASSPHRASE
  4. Set production gateway URLs:
    VITE_YOUR_MW_PAYFRAME_JS_URL
    VITE_YOUR_MW_PAYFRAME_URL
    VITE_YOUR_MW_SUBMIT_URL
  5. Configure EmailJS variables (optional):
    VITE_YOUR_EMAILJS_SERVICE_ID
    VITE_YOUR_EMAILJS_PUBLIC_KEY
    VITE_YOUR_ADMIN_EMAIL
  6. Run npm run build and deploy to your domain.
  7. Test with a live payment.
Tip: Use securetest.merchantwarrior.com URLs during testing and switch to secure.merchantwarrior.com for production.
Scenario B

Multi-Tenant SaaS Hosting

One deployment serves multiple organisations, each with its own merchant account, branding, and email configuration.

  1. Add a tenant configuration block for each organisation in src/config/tenantConfig.ts.
  2. In your hosting platform (Netlify, Vercel, etc.) set all tenant-prefixed environment variables (e.g., VITE_ALTIMA_MW_MERCHANT_UUID, VITE_CHARITY_MW_MERCHANT_UUID, …).
  3. Configure DNS: either wildcard CNAME (*.yourgateway.com) or path-based routing.
  4. Run a single npm run build — all tenants share the same build.
  5. Verify each tenant via URL parameter: ?tenant=your-tenant-id
  6. Test emails and payment processing for every tenant before go-live.
Tip: Adding a new tenant only requires a new config block and new environment variables — no rebuild of existing tenants needed.
Scenario C

Application Integration

Embed payment processing into an existing web application by redirecting to the gateway and handling the return URL.

  1. Ensure the gateway is running (any scenario above).
  2. Build a redirect URL with URL parameters:
    ?tenant=&amount=&name=&email=&phone=&address=&city=&postcode=&return_url=
  3. Redirect the user to the gateway URL.
  4. On your return page, read payment_status, transaction_id, and amount from the query string.
  5. Update your application state accordingly.
Streamlined Flow: When all required parameters (name, email, phone, address, city, postcode + amount/vatu) are passed via URL, the customer form is skipped entirely — the user proceeds directly to the card entry screen.
Scenario D

Development & Testing

Run locally against the Merchant Warrior test environment to develop and verify before going live.

  1. Clone the repository.
  2. Run npm install.
  3. Copy .env.example to .env.
  4. Leave test credentials as-is (safe defaults are already in the code).
  5. Confirm test URLs are set:
    VITE_MW_PAYFRAME_JS_URL=https://securetest.merchantwarrior.com/payframe/payframe.js
  6. Run npm run dev and open localhost:5173.
  7. Use the TenantSelector UI to switch between tenant configurations.
  8. Test using Merchant Warrior's published test card numbers.
Warning: Never use production credentials or live gateway URLs in development. Test credentials cannot process real transactions.

Environment Variable Quick Reference

All tenant environment variable names follow the pattern VITE_{TENANT_PREFIX}_{KEY} where the tenant prefix matches the tenant configuration block identifier (converted to uppercase, hyphens replaced with underscores).

Variable Pattern Purpose Required
VITE_{PREFIX}_MW_MERCHANT_UUIDMerchant Warrior merchant UUIDYes
VITE_{PREFIX}_MW_API_KEYMerchant Warrior API keyYes
VITE_{PREFIX}_MW_PASSPHRASEMerchant Warrior passphrase (for hash)Yes
VITE_{PREFIX}_MW_PAYFRAME_JS_URLPayFrame JS library URLYes
VITE_{PREFIX}_MW_PAYFRAME_URLPayFrame iFrame URLYes
VITE_{PREFIX}_MW_SUBMIT_URLTransaction submission URLYes
VITE_{PREFIX}_EMAILJS_SERVICE_IDEmailJS service identifierOptional
VITE_{PREFIX}_EMAILJS_PUBLIC_KEYEmailJS public keyOptional
VITE_{PREFIX}_EMAILJS_USER_SUCCESS_TEMPLATE_IDCustomer success email templateOptional
VITE_{PREFIX}_EMAILJS_USER_FAILURE_TEMPLATE_IDCustomer failure email templateOptional
VITE_{PREFIX}_EMAILJS_ADMIN_NOTIFICATION_TEMPLATE_IDAdmin notification templateOptional
VITE_{PREFIX}_ADMIN_EMAILAdmin email address for notificationsOptional
VITE_{PREFIX}_EXCHANGE_RATE_API_KEYexchangeratesapi.io key (VATU conversion)Optional
VITE_TENANT_IDForce a specific tenant (self-hosting)Self-host only
Gateway URLs by Environment: Test — securetest.merchantwarrior.com / base.merchantwarrior.com. Production — secure.merchantwarrior.com / api.merchantwarrior.com.

Overview & Features

Altima Pay is a modern, secure payment gateway built on Merchant Warrior PayFrame. It provides full multi-tenant support, enabling a single deployment to serve unlimited organisations with completely separate configurations, merchant accounts, and branding.

Production Ready: Enterprise-grade architecture supporting unlimited tenants from a single deployment, with complete configuration and credential isolation between tenants.

Live Demo & Tenant Reference

The application is deployed at:

https://altimapay.com/demo
TenantExample URLFeaturesStatus
Default
/?amount=50.00
Test credentials, basic features Demo
Altima Community
/?tenant=altima-community&vatu=5000
VATU converter, community branding Live
Gotoogle Pty Ltd
/?tenant=gotoogle&amount=100.00
Corporate branding, AUD payments Live
Freshwater Plantation Aore
/?tenant=freshwater-aore&vatu=10000
VATU converter, hospitality branding Live
StarFish Beach Bar Santo
/?tenant=starfish-santo&vatu=7500
VATU converter, beach bar branding Live
Altima Linux
/?tenant=altima-linux&amount=150.00
Tech branding, AUD only Live
Charity Network
/?tenant=charity-donations&amount=25.00
Charity branding, demo credentials Demo
Education Foundation
/?tenant=education-foundation&amount=75.00
Education branding, demo credentials Demo

Key Features

Multi-Tenant Architecture

Single deployment supporting unlimited organisations with separate configurations, merchant accounts, and branding.

Secure Payment Processing

Full integration with Merchant Warrior PayFrame for PCI DSS compliant card processing — no card data touches your servers.

Currency Conversion

Real-time VATU to AUD conversion using live exchange rates, configurable per tenant.

Email Notifications

Automated email confirmations for customers and admin notifications with complete text receipts including address and postcode.

URL Parameters

Pre-populate forms via URL parameters for seamless integration with existing applications and workflows.

Return to Application

Automatic return to spawning application with payment status, enabling complex multi-application workflows.

White-Label Solutions

Custom branding per tenant: company names, colours, logos, and feature toggles.

Responsive Design

Works on all devices with React 18, TypeScript, and Tailwind CSS.

Multi-Tenant Architecture

The application supports multiple tenant configurations without separate builds, enabling both hosted multi-tenancy and self-hosting scenarios with complete configuration isolation.

Tenant Detection & Configuration Flow

1. RequestUser accesses the application
2. DetectionSystem identifies tenant via priority chain
3. Config LoadTenant settings & credentials resolved
4. RenderBranding & features applied

Tenant Detection Methods

The system resolves the active tenant using the following priority order. The first method that returns a valid tenant ID wins.

PriorityMethodExampleUse Case
1 URL Parameter ?tenant=altima-community Dynamic switching, testing
2 URL Path /tenant/charity-donations/ RESTful routing
3 Subdomain altima.gateway.com Multi-tenant hosting
4 Environment Variable VITE_TENANT_ID=altima Self-hosting
5 Local Storage Persisted selection User preference
6 Default Test configuration Fallback

Detection Examples

# URL Parameter (highest priority)
https://paymentgateway.com/?tenant=altima-community&amount=50.00

# Path Method
https://paymentgateway.com/tenant/charity-donations/?amount=25.00

# Subdomain Method
https://altima.paymentgateway.com/?amount=100.00

# Self-Hosting (environment variable)
https://payments.altima-community.org/?amount=75.00

Tenant Configuration Structure

Each tenant can have completely separate settings across four areas:

Merchant Warrior Accounts

Different merchant UUIDs, API keys, passphrases, and gateway URLs per tenant.

Email Settings

Separate EmailJS configurations, templates, and admin email addresses.

Branding

Custom company names, colours, logos, and visual identity.

Feature Flags

Enable/disable VATU converter, email notifications, streamlined flow per tenant.

Tenant Configuration Example

'altima-community': {
  tenantId: 'altima-community',
  tenantName: 'Altima Community',
  merchantWarrior: {
    merchantUUID: import.meta.env.VITE_ALTIMA_MW_MERCHANT_UUID,
    apiKey:       import.meta.env.VITE_ALTIMA_MW_API_KEY,
    passphrase:   import.meta.env.VITE_ALTIMA_MW_PASSPHRASE,
    payframeJsUrl:import.meta.env.VITE_ALTIMA_MW_PAYFRAME_JS_URL,
    payframeUrl:  import.meta.env.VITE_ALTIMA_MW_PAYFRAME_URL,
    submitUrl:    import.meta.env.VITE_ALTIMA_MW_SUBMIT_URL,
  },
  email: {
    serviceId:  import.meta.env.VITE_ALTIMA_EMAILJS_SERVICE_ID,
    adminEmail: 'admin@altima-community.org',
    // ... template IDs
  },
  branding: {
    companyName:    'Altima Community',
    primaryColor:   '#059669',
    secondaryColor: '#047857',
    supportEmail:   'support@altima-community.org',
  },
  features: {
    vatuConverter:     true,
    emailNotifications: true,
    streamlinedFlow:   true,
    customReturnUrls:  true,
  }
}

Adding a New Tenant — 3 Steps

No core code changes required. Adding a tenant only touches the tenant config file and environment variables.
1

Add Tenant Configuration Block

Append a new block to src/config/tenantConfig.ts:

'your-organisation': {
  tenantId:   'your-organisation',
  tenantName: 'Your Organisation Name',
  merchantWarrior: {
    merchantUUID: import.meta.env.VITE_YOUR_MW_MERCHANT_UUID || 'test_fallback',
    apiKey:       import.meta.env.VITE_YOUR_MW_API_KEY       || 'test_fallback',
    passphrase:   import.meta.env.VITE_YOUR_MW_PASSPHRASE    || 'test_fallback',
    // ... other MW config
  },
  branding: {
    companyName:  'Your Organisation',
    primaryColor: '#007b8f',
    supportEmail: 'support@yourorganisation.com',
  },
  features: {
    vatuConverter:      false,
    emailNotifications: true,
    streamlinedFlow:    true,
    customReturnUrls:   true,
  }
}
2

Set Environment Variables

# Your Organisation — add to deployment platform environment
VITE_YOUR_MW_MERCHANT_UUID=live_merchant_uuid
VITE_YOUR_MW_API_KEY=live_api_key
VITE_YOUR_MW_PASSPHRASE=live_passphrase
VITE_YOUR_MW_PAYFRAME_JS_URL=https://secure.merchantwarrior.com/payframe/payframe.js
VITE_YOUR_MW_PAYFRAME_URL=https://secure.merchantwarrior.com/payframe/
VITE_YOUR_MW_SUBMIT_URL=https://api.merchantwarrior.com/payframe/
VITE_YOUR_EMAILJS_SERVICE_ID=service_your_org
VITE_YOUR_EMAILJS_PUBLIC_KEY=your_public_key
VITE_YOUR_ADMIN_EMAIL=admin@yourcompany.com
3

Deploy Once

A single build serves all tenants — existing and new — with zero downtime for other tenants.

Verify: Access ?tenant=your-organisation&amount=10.00 on the deployed app to confirm detection.

URL Parameters & Integration

The gateway accepts a comprehensive set of URL query parameters that pre-populate form fields, select tenants, configure amounts, and control post-payment behaviour.

URL Structure: The first parameter in a URL uses ?param=value. Every subsequent parameter uses &param=value. The examples in the tables below show each parameter as it would appear after other parameters are already present.

Tenant Selection

ParameterDescriptionExample
tenant Select a specific tenant configuration (overrides all other detection methods) ?tenant=altima-community
t Short-form alias for tenant ?t=charity-donations

Amount & Currency

ParameterDescriptionExample (as additional parameter)
amount Pre-fills the AUD amount directly and disables the VATU converter &amount=50.00
vatu Pre-fills a VATU amount and shows real-time AUD conversion &vatu=5000

Customer Information

These parameters pre-fill the customer form. When all required parameters are supplied (see Streamlined Flow), the form step is skipped entirely.

ParameterDescriptionExample (as additional parameter)
nameCustomer full name&name=John%20Doe
emailCustomer email address&email=john@example.com
phoneCustomer phone number&phone=+61400000000
addressStreet address&address=123%20Main%20St
cityCity or suburb&city=Sydney
stateState or province&state=NSW
postcodePostal / post code&postcode=2000
countryISO country code (defaults to AU)&country=AU
productProduct or service description&product=Computer%20Donation

Return URL

ParameterDescriptionExample (as additional parameter)
return_url URL to redirect to after payment completion (URL-encoded) &return_url=https%3A%2F%2Fmyapp.com%2Fdashboard
returnUrl Alternative camelCase alias for return_url &returnUrl=https%3A%2F%2Fmyapp.com%2Fdashboard

Integration Examples

Direct AUD Payment with Pre-filled Customer

https://altimapay.com/demo?tenant=altima-community&amount=75.50&name=John%20Doe&email=john@example.com&product=Computer%20Donation

VATU Conversion Payment

https://altimapay.com/demo?tenant=altima-community&vatu=10000&name=Mary%20Smith&email=mary@example.com&product=Education%20Support

Fully Pre-filled — Streamlined Flow (no form shown)

https://altimapay.com/demo?tenant=altima-community&vatu=5000&name=John%20Doe&email=john@example.com&phone=+61400000000&address=123%20Main%20St&city=Sydney&state=NSW&postcode=2000&country=AU&product=Altima%20Linux%20Computer

Payment with Return URL

https://altimapay.com/demo?tenant=charity-donations&amount=50.00&name=John%20Doe&email=john@example.com&return_url=https%3A%2F%2Fmyapp.com%2Fdashboard

JavaScript Integration Example

// Redirect to the payment gateway from your application
function initiatePayment(customerData, amount, tenant = 'default') {
  const baseUrl     = 'https://altimapay.com/demo';
  const returnUrl   = encodeURIComponent(window.location.origin + '/payment-complete');

  const params = new URLSearchParams({
    tenant,
    amount:     amount.toString(),
    name:       customerData.name,
    email:      customerData.email,
    phone:      customerData.phone,
    address:    customerData.address,
    city:       customerData.city,
    state:      customerData.state,
    postcode:   customerData.postcode,
    country:    customerData.country || 'AU',
    product:    customerData.product || 'Purchase',
    return_url: returnUrl,
  });

  window.location.href = baseUrl + '?' + params.toString();
}

// Handle the user returning from the gateway
function handlePaymentReturn() {
  const p             = new URLSearchParams(window.location.search);
  const paymentStatus = p.get('payment_status'); // 'success' | 'failed'
  const transactionId = p.get('transaction_id');
  const amount        = p.get('amount');

  if (paymentStatus === 'success') {
    console.log(`Payment OK — Transaction: ${transactionId}, Amount: $${amount}`);
  } else {
    console.log('Payment failed or cancelled');
  }
}

Return URL Parameters

After payment the gateway appends the following to the return_url:

ParameterDescriptionExample Values
payment_statusPayment outcomesuccess, failed
transaction_idMerchant Warrior transaction ID12345678
amountAmount charged in AUD50.00
tenantTenant that processed the paymentaltima-community

Payment Flow

The gateway supports two distinct flows depending on how much information is supplied via URL parameters.

Standard Flow

Used when partial or no customer information is pre-filled. The user completes a customer information form before proceeding to card entry.

1Tenant Detection
2Customer Form
3VATU Conversion (if enabled)
4PayFrame Card Entry
5Gateway Processing
6Response & Emails
7Return to App
  • Customer Information Form — user enters personal details; URL parameters pre-fill known fields.
  • Currency Conversion — optional VATU to AUD conversion with live exchange rates (tenant configurable).
  • Secure Payment — PayFrame loads card input fields hosted by Merchant Warrior.
  • Comprehensive Response — transaction receipt, download option, next-step buttons.
  • Email Notifications — customer confirmation and admin notification sent via tenant-specific templates.

Streamlined Flow

Trigger: All required parameters present in the URL — name, email, phone, address, city, postcode, plus amount or vatu.

When all required data is already known, the customer form is skipped and the user is taken directly to card entry.

1Tenant Detection
2Skip Form — direct to PayFrame
3Auto VATU Conversion (if applicable)
4PayFrame Card Entry
5Gateway Processing
6Simple Response & Emails
7Auto Return
  • Skip Form — no customer data entry step; user goes straight to card input.
  • Automatic VATU Conversion — AUD equivalent displayed if vatu parameter was used.
  • Simple Response — success shows a Finish button; failure shows a Retry button.
  • Automatic Return — seamless redirect to return_url with payment status parameters.
  • Minimal UI — focused, distraction-free interface suited for embedded scenarios.

Email Notifications

Both flows trigger email notifications on payment completion, sent via the tenant's configured EmailJS service.

Customer Email

Success or failure confirmation sent to the customer's email address. Uses tenant-specific success/failure templates.

Admin Notification

Full transaction details sent to the tenant's admin email, including a complete text receipt with customer address and postcode.

Admin emails include a receipt_text parameter containing a formatted plain-text receipt. Individual fields are also available as template variables: {{customer_address}}, {{customer_postcode}}, {{transaction_id}}, {{amount}}, etc.

Security & Configuration

Enterprise-grade security with comprehensive environment variable support. Sensitive configuration data is never hard-coded in production builds.

Environment Variables

Multi-Tenant Example

# Altima Community Tenant
VITE_ALTIMA_MW_MERCHANT_UUID=altima_live_uuid
VITE_ALTIMA_MW_API_KEY=altima_live_key
VITE_ALTIMA_MW_PASSPHRASE=altima_live_passphrase
VITE_ALTIMA_MW_PAYFRAME_JS_URL=https://secure.merchantwarrior.com/payframe/payframe.js
VITE_ALTIMA_MW_PAYFRAME_URL=https://secure.merchantwarrior.com/payframe/
VITE_ALTIMA_MW_SUBMIT_URL=https://api.merchantwarrior.com/payframe/
VITE_ALTIMA_EMAILJS_SERVICE_ID=service_altima
VITE_ALTIMA_EMAILJS_PUBLIC_KEY=altima_public_key
VITE_ALTIMA_EMAILJS_USER_SUCCESS_TEMPLATE_ID=template_altima_success
VITE_ALTIMA_EMAILJS_USER_FAILURE_TEMPLATE_ID=template_altima_failure
VITE_ALTIMA_EMAILJS_ADMIN_NOTIFICATION_TEMPLATE_ID=template_altima_admin
VITE_ALTIMA_ADMIN_EMAIL=admin@altima-community.org
VITE_ALTIMA_EXCHANGE_RATE_API_KEY=altima_fx_api_key

# Charity Tenant
VITE_CHARITY_MW_MERCHANT_UUID=charity_live_uuid
VITE_CHARITY_MW_API_KEY=charity_live_key
VITE_CHARITY_MW_PASSPHRASE=charity_live_passphrase
VITE_CHARITY_EMAILJS_SERVICE_ID=service_charity
VITE_CHARITY_EMAILJS_PUBLIC_KEY=charity_public_key
VITE_CHARITY_ADMIN_EMAIL=donations@charity.org

Self-Hosting Example

# Force a specific tenant
VITE_TENANT_ID=your-organisation

# Gateway credentials
VITE_YOUR_MW_MERCHANT_UUID=your_merchant_uuid
VITE_YOUR_MW_API_KEY=your_api_key
VITE_YOUR_MW_PASSPHRASE=your_passphrase
VITE_YOUR_MW_PAYFRAME_JS_URL=https://secure.merchantwarrior.com/payframe/payframe.js
VITE_YOUR_MW_PAYFRAME_URL=https://secure.merchantwarrior.com/payframe/
VITE_YOUR_MW_SUBMIT_URL=https://api.merchantwarrior.com/payframe/

# Email notifications
VITE_YOUR_EMAILJS_SERVICE_ID=service_your_org
VITE_YOUR_EMAILJS_PUBLIC_KEY=your_public_key
VITE_YOUR_ADMIN_EMAIL=admin@yourcompany.com

Gateway URLs by Environment

EnvironmentPayFrame JS URLPayFrame URLSubmit URL
Test securetest.merchantwarrior.com/payframe/payframe.js securetest.merchantwarrior.com/payframe/ base.merchantwarrior.com/payframe/
Production secure.merchantwarrior.com/payframe/payframe.js secure.merchantwarrior.com/payframe/ api.merchantwarrior.com/payframe/

Security Best Practices

Development: Test credentials are safely included as code fallbacks. All URLs point to Merchant Warrior's test environment. No real payments can be processed. The test configuration may be safely committed to version control.
Production: Never commit .env files containing live credentials. Always store production credentials as environment variables in your hosting platform. Add .env, .env.local, and .env.production to .gitignore.
Security LayerImplementationBenefit
Payment ProcessingMerchant Warrior PayFramePCI DSS compliant — card data never touches the application
API AuthenticationMD5 hash with passphrase + multiple elementsTamper-evident API communication
Data TransmissionHTTPS / TLSAll data encrypted in transit
ConfigurationEnvironment variables (Vite prefix)Credentials never exposed in source code
Input ValidationClient-side form validationPrevents malformed data reaching the gateway
Tenant IsolationDynamic configuration loadingComplete separation between tenant credentials
Card DataMasked card numbers only (last 4 digits)PCI compliance — no full card data stored or emailed

Deployment & Hosting

The application supports multiple deployment scenarios — from a multi-tenant SaaS platform serving dozens of organisations to a self-hosted single-organisation installation.

Multi-Tenant Hosting

A single build serves all configured tenants. Tenant routing is resolved by subdomain, URL path, or query parameter.

1Add tenant configs
2Set all env variables in hosting platform
3Single npm run build
4Configure DNS / routing

DNS — Subdomain Routing

# Wildcard CNAME covers all tenants automatically
*.yourgateway.com        → yourgateway.com
altima.yourgateway.com   → yourgateway.com
charity.yourgateway.com  → yourgateway.com

Benefits of Multi-Tenant Hosting

Cost Effective

One deployment, one maintenance contract, unlimited tenants.

Easy Updates

Deploy once to push security patches and new features to all tenants simultaneously.

Scalable

Add tenants by config block + env vars — no infrastructure changes.

Isolated

Complete credential and configuration separation between tenants.

Self-Hosting

Deploy on your organisation's own domain with custom branding by forcing a single tenant via environment variable.

1

Set Tenant ID

VITE_TENANT_ID=your-organisation
2

Configure Credentials

VITE_YOUR_MW_MERCHANT_UUID=live_uuid
VITE_YOUR_MW_API_KEY=live_key
VITE_YOUR_MW_PASSPHRASE=live_passphrase
VITE_YOUR_MW_PAYFRAME_JS_URL=https://secure.merchantwarrior.com/payframe/payframe.js
VITE_YOUR_MW_PAYFRAME_URL=https://secure.merchantwarrior.com/payframe/
VITE_YOUR_MW_SUBMIT_URL=https://api.merchantwarrior.com/payframe/
VITE_YOUR_EMAILJS_SERVICE_ID=service_id
VITE_YOUR_EMAILJS_PUBLIC_KEY=public_key
VITE_YOUR_ADMIN_EMAIL=admin@yourcompany.com
3

Deploy to Your Domain

payments.yourcompany.com
pay.yourorganisation.org
gateway.yourbusiness.net
Benefits: Full control over visual identity, custom domain, meets internal compliance requirements, easier integration with internal systems.

Hosting Platform Examples

Netlify

Set environment variables under Site Settings → Environment Variables. Enable branch deploy previews for staging. Configure redirect rules for SPA routing:

# netlify.toml
[[redirects]]
  from = "/*"
  to   = "/index.html"
  status = 200

Vercel

Set environment variables under Project Settings → Environment Variables. Vercel handles SPA rewrites automatically for Vite projects.

Any Static Host (S3, GitHub Pages, cPanel)

Build locally with npm run build, upload the dist/ folder, and configure your server to serve index.html for all routes (SPA fallback).

Technical Reference

Architecture, technology stack, component structure, and API integration details.

Technology Stack

LayerTechnologyPurpose
Frontend FrameworkReact 18 + TypeScriptType-safe component UI
Build ToolViteFast builds and HMR in development
StylingTailwind CSSUtility-first responsive CSS
Payment ProcessingMerchant Warrior PayFramePCI DSS compliant card capture (hosted fields)
Email ServiceEmailJSClient-side email dispatch (no server required)
Currency APIexchangeratesapi.ioReal-time VUV → AUD exchange rates
IconsLucide ReactSVG icon library
State ManagementReact HooksLocal component and shared state
Hash Utilitycrypto-jsMD5 hash generation for Merchant Warrior auth

Component & File Structure

src/
├── components/
│   ├── CustomerForm.tsx          # Customer information form
│   ├── VatuConverter.tsx         # VATU → AUD conversion display
│   ├── PayFrameContainer.tsx     # Merchant Warrior PayFrame wrapper
│   ├── PaymentResponse.tsx       # Transaction result screen
│   ├── SurchargeDisplay.tsx      # Surcharge calculation display
│   └── TenantSelector.tsx        # Dev-only tenant switcher
├── services/
│   ├── emailService.ts           # Tenant-aware EmailJS integration
│   ├── receiptService.ts         # Text receipt generation
│   ├── fxService.ts              # Exchange rate API service
│   └── currencyService.ts        # Currency formatting utilities
├── config/
│   ├── tenantConfig.ts           # Multi-tenant configuration map
│   ├── settings.ts               # Legacy settings (backward compat)
│   └── merchantWarrior.ts        # Dynamic payment gateway config
├── hooks/
│   ├── useUrlParams.ts           # URL parameter parsing
│   └── useTenantColors.ts        # CSS variable injection for branding
└── types/
    └── payment.ts                # TypeScript interfaces

Application State Machine

The top-level App component manages a simple three-state flow:

formCustomer information collection (skipped in streamlined mode)
paymentPayFrame card entry and submission
responseTransaction result, email dispatch, return URL

API Integration — Return URL Handling

Express.js Example

// Server-side return URL handler
app.get('/payment-complete', async (req, res) => {
  const { payment_status, transaction_id, amount, tenant } = req.query;

  if (payment_status === 'success') {
    console.log(`Payment OK — ${transaction_id} for $${amount} (${tenant})`);

    switch (tenant) {
      case 'altima-community':
        await processEducationDonation(transaction_id, amount);
        break;
      case 'charity-donations':
        await processCharityDonation(transaction_id, amount);
        break;
    }
  }

  res.redirect('/dashboard');
});

React Component Example

function PaymentButton({ customerData, amount, tenant }) {
  const initiatePayment = () => {
    const params = new URLSearchParams({
      tenant,
      amount:     amount.toString(),
      name:       customerData.name,
      email:      customerData.email,
      phone:      customerData.phone,
      address:    customerData.address,
      city:       customerData.city,
      state:      customerData.state,
      postcode:   customerData.postcode,
      country:    customerData.country || 'AU',
      product:    customerData.product || 'Purchase',
      return_url: encodeURIComponent(window.location.origin + '/payment-complete'),
    });
    window.location.href = 'https://altimapay.com/demo?' + params.toString();
  };

  return <button onClick={initiatePayment}>Pay ${amount} AUD</button>;
}

Troubleshooting & Support

Common issues, their causes, and solutions. For all issues, start by opening the browser developer console — the application logs detailed configuration and error information.

Tenant Detection Issues

SymptomLikely CauseSolution
Wrong tenant loads Conflicting detection methods (e.g., localStorage vs URL param) Check priority order. Clear localStorage: localStorage.removeItem('tenantId')
Default config always loads Tenant ID not found in tenantConfig.ts Verify the ID matches exactly (case-sensitive, hyphens preserved)
Subdomain not detected DNS CNAME not propagated or missing wildcard record Check CNAME records; allow up to 48 hours for DNS propagation
Environment variable ignored Variable name typo or wrong prefix Verify prefix matches tenant config key (uppercase, underscores for hyphens)

Payment Processing Issues

SymptomLikely CauseSolution
PayFrame does not load Incorrect Merchant Warrior UUID, API key, or passphrase Verify all three MW credentials for the active tenant
Payment fails with hash error Passphrase mismatch or encoding issue Check passphrase — no leading/trailing spaces, correct character encoding
Test cards not working Live gateway URL used with test credentials Ensure securetest.merchantwarrior.com URLs are set for test environment
Live payments not processed Test gateway URL used in production Switch to secure.merchantwarrior.com and api.merchantwarrior.com

Email Notification Issues

SymptomLikely CauseSolution
No emails sent at all EmailJS service ID or public key not configured Verify VITE_{PREFIX}_EMAILJS_SERVICE_ID and VITE_{PREFIX}_EMAILJS_PUBLIC_KEY
Customer emails missing Template ID not set or set to placeholder value Check VITE_{PREFIX}_EMAILJS_USER_SUCCESS_TEMPLATE_ID
Admin email not sent Admin email address not configured or template missing Verify VITE_{PREFIX}_ADMIN_EMAIL and admin template ID
Template variables show blank Mismatch between parameter names sent and template variable names Check EmailJS template uses correct variable names (e.g., {{customer_postcode}})

Debugging Tools

Use browser DevTools console — the application logs verbose tenant detection and configuration details on every page load.

Browser Console Debug Commands

// Check which tenant is active
console.log('Tenant:', getCurrentTenantConfig());

// Check email configuration status
EmailService.initialize(); // Logs all config checks to console

// Manually set tenant via localStorage (for testing)
localStorage.setItem('tenantId', 'altima-community');
location.reload();

Testing Tenant Detection Methods

# 1. URL Parameter (append to any URL)
?tenant=altima-community&amount=10.00

# 2. Path-based
/tenant/charity-donations/?amount=25.00

# 3. Subdomain (requires DNS)
https://altima.yourgateway.com/?amount=10.00

# 4. Environment variable (rebuild required)
VITE_TENANT_ID=altima-community

# 5. localStorage (browser console)
localStorage.setItem('tenantId', 'charity-donations');

Support Resources

Documentation

  • README.md — general setup and configuration
  • DEPLOYMENT.md — platform-specific deployment guides
  • TEXT_RECEIPT_SETUP.md — EmailJS template configuration
  • SECURITY.md — security model and practices

External Resources

  • Merchant Warrior Developer Documentation
  • EmailJS Documentation — emailjs.com/docs
  • exchangeratesapi.io for currency API keys
  • Vite documentation for build configuration