Skip to main content

Cordova SDK — Integration Guide

AI coding agents

Fetch the integration-path skill for machine-readable setup guidance and code examples: /.well-known/skills/paths/cordova.md

What is this integration path?​

The Handpoint Cordova plugin (cordova-plugin-handpoint) brings payment capabilities to cross-platform Cordova and Ionic applications. It supports both PAX SmartPOS terminals (via Cloud) and HiLite Bluetooth readers.

Choose this path when your team is already building in Cordova or Ionic and wants payment without a separate native SDK.

When to use it​

✅ Good fit❌ Not a good fit
Your app is built with Cordova or IonicYou're building a native Android app — use the Android PAX or Android HiLite path
You need a single codebase for Android and iOSYou need iOS + HiLite — the iOS HiLite path is the native option
You're targeting PAX Cloud or HiLite BluetoothYou need advanced pre-auth — not supported on HiLite via Cordova
Back-office operations are always available

Backoffice REST API operations — tip adjustment, reversals, refunds, MOTO charges, batch management, deferred tokenization — are available alongside any integration path you choose. They go server-side directly to the payment gateway with no terminal or SDK required. Subject only to acquirer support.

Capabilities not available on HiLite via Cordova​

  • Pre-authorization
  • MOTO / remote sale on-terminal

How it works​

Your Cordova / Ionic App
│ HAPI.sale({ amount, currency })
▼
cordova-plugin-handpoint
│ Cloud (PAX) or Bluetooth (HiLite)
▼
PAX Terminal or HiLite Reader
│ chip / tap / swipe + P2PE
▼
handpoint.endOfTransaction DOM event

Authentication​

CredentialPurposeProvisioned by
apiKeyMerchant API key for Cloud connectionHandpoint Integration Support
sharedSecretFor Bluetooth (HiLite) — authenticates to readerHandpoint Integration Support

Setup​

1. Request credentials​

Contact your Handpoint Integration Support engineer for:

  • A merchant API key (PAX Cloud) or shared secret (HiLite)
  • A PAX DEMO terminal or HiLite reader

2. Install the plugin​

Cordova:

cordova plugin add cordova-plugin-handpoint

Ionic:

npm install cordova-plugin-handpoint
ionic cap sync

3. Initialise​

// PAX SmartPOS (Cloud path)
handpoint.setup({
sharedSecret: 'YOUR_SHARED_SECRET',
automaticReconnection: true
}, successCallback, errorCallback);

// HiLite Bluetooth path
handpoint.setup({
sharedSecret: 'YOUR_SHARED_SECRET',
automaticReconnection: true
}, successCallback, errorCallback);

Call handpoint.setup() once on app start. Do not re-initialise per transaction.

4. Register event listeners​

// Transaction result
document.addEventListener('handpoint.endOfTransaction', function(event) {
const result = event.detail.transactionResult;
handleResult(result);
});

// Device discovery (HiLite Bluetooth path)
document.addEventListener('handpoint.deviceDiscoveryFinished', function(event) {
const devices = event.detail.devices;
if (devices.length > 0) {
HAPI.connect({ deviceName: devices[0].name }, success, error);
}
});

5. Connect to a terminal​

PAX Cloud:

// Connect by device name (serial-model format)
HAPI.connect({ deviceName: '0821032395-PAXA920' }, successCallback, errorCallback);

HiLite Bluetooth — discovery:

HAPI.startMonitoring(successCallback, errorCallback);
// deviceDiscoveryFinished event fires with the list

Your first transaction​

// Amount in smallest currency unit — £10.00 = 1000
HAPI.sale({
amount: 1000,
currency: 'GBP',
customerReference: 'ORDER-123'
}, successCallback, errorCallback);

// Result arrives in handpoint.endOfTransaction event

Reading the result​

document.addEventListener('handpoint.endOfTransaction', function(event) {
const result = event.detail.transactionResult;
const status = result.finStatus; // 'AUTHORISED', 'DECLINED', etc.
const txId = result.transactionID; // store for reversals and refunds

switch (status) {
case 'AUTHORISED':
db.markPaid(txId);
break;
case 'DECLINED':
case 'CANCELLED':
case 'FAILED':
db.clearPending();
break;
case 'UNDEFINED':
// Do not retry — recover via getTransactionStatus
startBackgroundRecovery(savedTransactionReference);
break;
}
});
UNDEFINED means unknown — do not retry

UNDEFINED indicates no result was received (e.g. connection dropped after card tap). The transaction may have processed. Always recover via HAPI.getTransactionStatus() before retrying.

Transaction recovery​

Always save a transactionReference you generate before starting any operation.

const transactionReference = generateUUID();
db.savePendingTransaction(transactionReference);

HAPI.sale({
amount: 1000,
currency: 'GBP',
transactionReference: transactionReference
}, success, error);

On UNDEFINED or app restart with a pending reference:

function startBackgroundRecovery(ref) {
HAPI.getTransactionStatus(
{ transactionReference: ref },
function(result) {
if (result.finStatus === 'IN_PROGRESS' || result.finStatus === 'UNDEFINED') {
// Poll again in 10 s
setTimeout(() => startBackgroundRecovery(ref), 10_000);
return;
}
// Wait 60 s before acting (covers PARTIAL_APPROVAL window)
setTimeout(() => {
if (result.finStatus === 'AUTHORISED') {
sendReversal(result.transactionID);
}
db.clearPending(ref);
}, 60_000);
},
function(error) {
console.error('getTransactionStatus error:', error);
}
);
}

// On app startup
const pending = db.getPendingTransaction();
if (pending) startBackgroundRecovery(pending.ref);

→ Full implementation: Transaction Recovery — Cordova SDK

Operations available​

OperationMethod
SaleHAPI.sale({ amount, currency, customerReference? })
RefundHAPI.refund({ amount, currency, originalTransactionID? })
ReversalHAPI.reversal({ originalTransactionID, amount? })
Pre-AuthorizationHAPI.preAuthorization({ amount, currency }) — PAX only
Pre-Auth CaptureHAPI.preAuthorizationCapture({ amount, originalTransactionID }) — PAX only
Pre-Auth ReversalHAPI.preAuthorizationReversal({ originalTransactionID }) — PAX only
Tip AdjustmentHAPI.tipAdjustment({ tipAmount, originalTransactionID })
Get Transaction StatusHAPI.getTransactionStatus({ transactionReference })
Stop TransactionHAPI.stopCurrentTransaction()

Acquirer-specific availability: see your acquirer's page for supported features: EPI · PAYSAFE · EmerchantPay · Paystrax.

Test amounts​

Pass amounts in minor units (cents / pence). Use the full trigger table — including partial approval (3757) and timeout (3768) — from Development Hardware: Testing with trigger amounts. Any amount not in the table approves.

Validation & certification​

Required for every integration:

  • transactionReference generated and persisted before each HAPI.sale() call — scoping rules
  • handpoint.endOfTransaction listener registered before any transaction starts
  • UNDEFINED recovery flow implemented and tested
  • App-restart recovery — pending reference polled on startup
  • Partial approval handled — PARTIAL_APPROVAL detected; collect split tender or send automatic reversal (partial approval guide)

→ Full scenario checklist: Validate your integration

→ Error codes: Error codes

See Also​