Tutorial: payments

payments

MeldCX Agent Payments API

Terminology

Term Description
Payment Gateways Is the interface responsible for crafting the transaction message and handling the responses
Payment Terminal Is the peripheral device responsible for providing the payload ‘card data’ to the Gateway

Configuration

The payment API supports configuring the various properties of the API Engine, Gateway and Terminal using the following configuration mechanisms:

  • Application manifest, manifest.json file stored in the root of your application folder (alongside index.html)
  • Account Preferences
  • Device Options
  • Display Options
  • Explicit configuration via Agent.Payments.setConfiguration, Agent.Payments.setGatewayConfiguration and Agent.Payments.setTerminalConfiguration

The available configuration properties are as follows

Property Name Optional Description Supported Values Default Value Example Value
Payment.Gateways No List of comma seperated values, defines the available payment gateways MockGateway, FreedomPayFreeway null MockGateway
Payment.Terminal Yes This only required when you are using a non dynamically discoverable terminal such as the MockTerminal MockTerminal null MockTerminal

There are additional values for each Terminal and Gateway see the Payment Terminals section for the various Terminal configuration options and the Payment Gateways section for the various Gateway configuration options.

Payment Terminals

Some terminals require configuration to setup the devices for Styling, Behavioural restrictions and other configuration.

Available Terminals

The currently terminals supported by MeldCX are:

Model Configuration Name Capabilities
IDTech VP6800 IDTechVP6800 MSR, EMV with PIN, Contact with PIN, Apple Pay, Google Pay, Manual Entry
IDTech VP8800 IDTechVP8800 MSR, EMV with PIN, Contact with PIN, Apple Pay, Google Pay, Manual Entry
MockTerminal MockTerminal N/A

Configuration

Configuration of the terminals can be done using any of the configuration mechanisms listed in Configuration, the configuration is structured as follows:

Configuration Key Optional Configuration Value
Payment.{Configuration Name} No See Independant Terminal Section
Payment.Terminal.PairMode No (Choose 1) Silent, Interactive
Payment.Terminal.PairStrategy No (Choose 1) serialNumberOnly, keyOnly, serialNumberAndKeys (Silent), CodeOnScreen (Interactive)

Pairing Payment Terminal/Pin Pad

It is necessary to ensure that the terminal we are communicating with is authorised in order to do this we use the process of pairing to validate the terminal.

If the Payments Engine has not paired with a device it will be in the TerminalPairingFailed state which can be validated using the Agent.Payments.status() function.

Pairing Mode

The following pairing modes are supported:

  • Silent - Doesn't require any user interaction to pair with the terminal
  • Interactive - Requires user interaction to pair the terminal
Configuration Key Optional Configuration Value
Payment.Terminal.PairMode No (Choose 1) Silent, Interactive

Pairing Strategy

The supported pairing strategies are as follows:

Pairing Mode - Interactive

The following Interactive pairing strategies are available:

Note: These are available only if using the Interactive Pairing Mode.

Option Name Option Value Optional
Payment.Terminal.PairStrategy codeOnScreen No
Interactive Pairing Stragegy - Code On Screen

Using the Agent.Payments.pairInteractiveCommence() function to invoke the device to go into pairing mode and show a pairing code on screen.

Call the Agent.Payments.pairInteractiveComplete() function and provide the pairingCode as the property on the object provided to the function for example.

await Agent.Payments.pairInteractiveCommence();

// Pairing Code will be displayed on terminal screen

const result = await Agent.Payments.pairInteractiveComplete({pairingCode: 123456});

if (result) console.log('Pairing Succeeded');
else console.log('Pairing Failed');

// Validate that the pairing succeeded and that the Payments Engine is ready to take payments

const status = await Agent.Payments.status();

if (status.message === 'Ready') console.log('Payments Engine is ready!');
else console.log('Payments Engine is not ready');

The Agent will then store unique identification information about this pinpad and trust the device automatically from this point forward until Agent.Payments.unPair() is called.

Silent Pairing Strategies

The following Silent pairing strategies are available.

Configuration Key Configuration Value Optional
Payment.Terminal.PairStrategy serialOnly, keyOnly, serialNumberAndKeys No (Choose One)
Serial Number Only

This strategy enables pairing based on matching the serial number only.

This can be configured in the device options as follows:

Option Name Option Value Optional
Payment.Terminal.PairStrategy serialNumberOnly No
Payment.Terminal.SerialNumber Device Serial Number No
Encryption Key Only

This strategy enables pairing based on matching the Encyrption Key KSN and Type.

This can be configured in the device options as follows:

Option Name Option Value Optional
Payment.Terminal.PairStrategy keyOnly No
Payment.Terminal.PairStrategy.ksn Encryption Key KSN No
Payment.Terminal.PairStrategy.type Encryption Key Type No

Serial Number and Encryption Key

This strategy enables pairing based on matching the serial number and the Encyrption Key KSN and Type.

This can be configured in the device options as follows:

Option Name Option Value Optional
Payment.Terminal.PairStrategy serialNumberAndKeys No
Payment.Terminal.SerialNumber ID Tech Device Serial Number No
Payment.Terminal.PairStrategy.ksn Encryption Key KSN No
Payment.Terminal.PairStrategy.type Encryption Key Type No

Silent Pairing

Silent Pairing is run automatically or can be invoked using the Agent.Payments.pairSilent() function, this will resolve to true or false depending on if the pairing was a success.

Interactive Pairing

Interactive Pairing is invoked manually using the Agent.Payments.pairInteractiveCommence() function and providing any neccessary parameters, this will invoke the terminal to start the interactive pairing sequence. To complete the interactive pairing simply call Agent.Payments.pairInteractiveComplete() function and provide any neccessary parameters (see independant terminal section.)

IDTech VP6800 & VP8800

Option Name Description Available Values Example Optional
Payment.IDTechVP6800.interfaces Define which interfaces/mechanisms to use for payment transactions, comma seperated. MSR, Contact, Contactless MSR No
Payment.IDTechVP8800.interfaces Define which interfaces/mechanisms to use for payment transactions, comma seperated. MSR, Contact, Contactless MSR No

Mock Terminal

You can invoke failure modes by making a transaction with the total value in the charges set to the corresponding value in the table below.

Failure Mode Total Value
Rejected 1.66

Payment Gateways

The available payment gateways are:

  • FreedomPay Freeway
  • Mock Gateway

Mock Gateway

The mock gateway is intended to be used for debugging, testing and setting up your initial integration with this API.

Configuration

You can invoke failure modes by making a transaction with the total value in the charges set to the corresponding value in the table below.

Failure Mode Total Value
Declined 1.66

You can configure other aspects of the mock gateway using configuration options, see below.

Name Supported Values Notes Optional
status Status.Up, Status.Down Emulate the status of the Gatreay. Can be imported using import {Status} from '@meldcx/agent-payments'; Yes
defaultLoter 1000+ The amount of time in milliseconds to wait between transaction stages Yes

FreedomPay Freeway

Configuration

The following configuration options are available for the FreedomPay Freeway gateway:

The payment API supports a heirarchical system that applies the configuration in a cascading order of the following: manifest.json, Account Preferences, Device Options and Display Options.

The bulk of these options should be pre-configured as account preferences, however some values such as terminalId may be kiosk specific.

Option Name Option Value Option Example
Payment.FreedomPayFreeway.storeID The Store ID value provided by FreedomPay 1234
Payment.FreedomPayFreeway.terminalId The Terminal ID value provided by FreedomPay 7890
Payment.FreedomPayFreeway.maxFreewaySvrDelta Allowable time diff between FP svr and client 60000
Payment.FreedomPayFreeway.endpoint The SOAP API Endpoint to be used https://cs.uat.freedompay.com/Freeway/Service.asmx
Payment.FreedomPayFreeway.endpointHealthUrl The SOAP API Health Endpoint to be used https://cs.uat.freedompay.com/Freeway/HealthCheck.ashx
Payment.FreedomPayFreeway.cardStorEndpointUrl The SOAP API Endpoint for CardStor https://cs.uat.freedompay.com/CardStor/CardStorService.asmx
Payment.FreedomPayFreeway.currency The currency to use. USD
Payment.FreedomPayFreeway.industryType The Industry Type (See FreedomPay Documents) hotel
Payment.FreedomPayFreeway.platform The OS being used** ChromeOS
Payment.FreedomPayFreeway.hostname The Host name of the kiosk device** New York Marriott Downtown - Kiosk 1
Payment.FreedomPayFreeway.deviceId The ID of the Register/Kiosk Device* 1234567

* This will be populated automatically by MeldCX (can be overridden) and will reference the MeldCX Unique device ID.

** This will be populated automatically by MeldCX (can be overridden).

You can invoke failure modes by making a transaction with the total value in the charges set to the corresponding value in the table below.

Failure Mode Total Value
Declined 55.01
Failure 55.06
Delayed 55.03

Errors

FreedomPay Freeway Errors will have the following format:

Exception Name Code Description
PaymentGatewayException {FreedomPay Freeway Specific} See Freedompay error guide here

Minimum Configuration with ID Tech VP6800 & VP8800 Payment Terminals

The Minimum configuration required for the payments setup in development is as follows:

Option Name Option Value
Payment.Gateways MockGateway
Payment.IDTechVP6800.interfaces MSR * FOR VP6800 ONLY
Payment.IDTechVP8800.interfaces MSR * FOR VP8800 ONLY
Payment.Terminal.PairStrategy serialNumberOnly
Payment.Terminal.PairMode Silent
Payment.Terminal.SerialNumber {Serial No off the back of the terminal}

Minimum Configuration without Payment Terminal

Option Name Option Value
Payment.Gateways MockGateway
Payment.Terminal MockTerminal

Transaction Types

The available transaction types are as follows:

Type Code
Payment 1
Capture 2
PreAuth 4
Credit 8
Refund 16
Token 32

These Transaction types can be referenced using the Agent.Payments.TransactionType property or imported from the @meldcx/agent-payments NPM library as follows:

import {TransactionType} from '@meldcx/agent-payments';

Reference Information

All transactions require that you provide reference information for tracking the state and maintaing records of your transactions. The supported fields for the reference information object are as follows:

Name Description Optional
id A generic ID Yes
invoiceNumber An invoice number No (FreedomPay)
invoiceDate A related invoice date in ISO-8601 Date Format No (FreedomPay)

Some gateways require different information to be provide as the reference for the transaction, below is a list of reference information required by each gateway implemented by MeldCX

Gateway Required reference fields
MockGateway Any
FreedomPay Freeway invoiceNumber (MAX 20 CHARS), invoiceDate

Charges

All transactions require that you provide a charges object containing all of the charges to be applied.

Name Description Optional
total The total amount to charge No (Yes for Credit and Void Transactions)
tax The amount of tax in this charge Yes
tip The tip amount in this charge Yes
cashout The amount of cash out in this charge Yes
credit The amount to credit Yes (No for Credit Transaction)

Performing Transactions

Performing a transaction is done using the Agent.Payments.startTransaction() function.

To peform a payment transaction you need to provide the following parameters:

Payment Transaction

Performing a Payment Transaction can be done like so:

import {PaymentException} from '@meldcx/agent-payments';
import Agent from '@meldcx/agent';
import moment from 'moment';

const agent = new Agent();
const transactionType = agent.Payments.TransactionType.Payment;
const reference = { invoiceNumber: 'ABC1234DEF', invoiceDate: (new Date()).toISOString() };
const charges = { total: 100, tax: 10 };

try {
    const result = await agent.Payments.startTransaction(transactionType, reference, charges, options);
    console.log('Transaction Was Approved', result);
} catch (ex) {
    if (ex instanceof TransactionRejectedException) {
        const {responseCode, code} = ex;

        console.log(`Transaction was rejected: ${code} with response code: ${responseCode}`);

        return;
    }

    console.log(`Some other error occurred: ${ex.code}`);
}

Performing a pre-auth Transaction can be done like so, additionally we have added line items for this pre-auth:

import {PaymentException} from '@meldcx/agent-payments';
import Agent from '@meldcx/agent';
import moment from 'moment';

const agent = new Agent();
const transactionType = agent.Payments.TransactionType.PreAuth;
const reference = { invoiceNumber: 'DEF383832', invoiceDate: (new Date()).toISOString() };
const charges = { total: 100, tax: 10 };

// NOTE: Items are not mandatory, they only need to be provided once for a given transaction reference. i.e. Provided with pre-auth but absent from capture.
const items = [
    {
        folioNumber: 7741234,
        expectedDuration: 2,
        noShow: false,
        checkinDate: moment().toISOString(),
        checkoutDate: moment().add(2, 'days').toISOString(),
        extraChargeType: 'M',
        roomRate: 50,
        roomTax: 5,
        extraChargeTotal: 0
    }
];
const options = { items };
try {
    const result = await agent.Payments.startTransaction(transactionType, reference, charges, options);
    console.log('Transaction Was Approved', result);
} catch (ex) {
    if (ex instanceof TransactionRejectedException) {
        const {responseCode, code} = ex;

        console.log(`Transaction was rejected: ${code} with response code: ${responseCode}`);

        return;
    }

    console.log(`Some other error occurred: ${ex.code}`);
}

Capturing a prior transaction

import {PaymentException} from '@meldcx/agent-payments';
import Agent from '@meldcx/agent';

const agent = new Agent();
let transactionType = agent.Payments.TransactionType.PreAuth;
const reference = { invoiceNumber: 'DEF383832', invoiceDate: (new Date()).toISOString() };
const charges = { total: 100, tax: 10 };

let result = await agent.Payments.startTransaction(transactionType, reference, charges);

reference.id = result.response.requestID;

transactionType = agent.Payments.TransactionType.Capture;

result = await agent.Payments.startTransaction(transactionType, reference, charges);

Making a Credit transaction:

import {PaymentException} from '@meldcx/agent-payments';
import Agent from '@meldcx/agent';

const agent = new Agent();
const transactionType = agent.Payments.TransactionType.Credit;
const reference = { invoiceNumber: 'DEF383832', invoiceDate: (new Date()).toISOString() };
const charges = { total: 100};

try {
    const result = await agent.Payments.startTransaction(transactionType, reference, charges);
    console.log('Transaction Was Approved', result);
} catch (ex) {
    if (ex instanceof TransactionRejectedException) {
        const {responseCode, code} = ex;

        console.log(`Transaction was rejected: ${code} with response code: ${responseCode}`);

        return;
    }

    console.log(`Some other error occurred: ${ex.code}`);
}

Cancel a Transaction:

Note: If the transaction doesn't cancel, you may still need to make a reversal/credit transaction.

import {PaymentException} from '@meldcx/agent-payments';
import Agent from '@meldcx/agent';

const agent = new Agent();
const transactionType = agent.Payments.TransactionType.Capture;
const reference = { invoiceNumber: 'DEF383832', invoiceDate: (new Date()).toISOString() };
const charges = { total: 100, tax: 10 };

try {
    setTimeout(() => agent.Payments.cancelTransaction(reference));
    const result = await agent.Payments.startTransaction(transactionType, reference, charges);
    console.log('Transaction Was Approved', result);
} catch (ex) {
    if (ex instanceof AgentCancelledException) {
        const {code} = ex;

        console.log(`Transaction was cancelled: ${code}`);

        return;
    }

    console.log(`Some other error occurred: ${ex.code}`);
}

Making a PreAuth and Token transaction:

import {PaymentException} from '@meldcx/agent-payments';
import Agent from '@meldcx/agent';

const agent = new Agent();
const transactionType = agent.Payments.TransactionType.PreAuth | agent.Payments.TransactionType.Token;
const reference = { invoiceNumber: 'DEF383832', invoiceDate: (new Date()).toISOString() };
const charges = { total: 50};

try {
    const result = await agent.Payments.startTransaction(transactionType, reference, charges);
    console.log('Transaction Was Approved', result);
    console.log('Token is:', result.response.token);
} catch (ex) {
    if (ex instanceof TransactionRejectedException) {
        const {responseCode, code} = ex;

        console.log(`Transaction was rejected: ${code} with response code: ${responseCode}`);

        return;
    }

    console.log(`Some other error occurred: ${ex.code}`);
}

Voiding a prior transaction:

import {PaymentException} from '@meldcx/agent-payments';
import Agent from '@meldcx/agent';

const agent = new Agent();
let transactionType = agent.Payments.TransactionType.PreAuth;
const reference = { invoiceNumber: 'DEF383832', invoiceDate: (new Date()).toISOString() };
const charges = { total: 50};

let result = await agent.Payments.startTransaction(transactionType, reference, charges);

reference.id = result.response.requestID;

transactionType = agent.Payments.TransactionType.Void;
result = await agent.Payments.startTransaction(transactionType, reference, charges);

Transaction Status

You can listen to transaction status updates by register an event listener using the function onTransactionStatus and example of this is below:

Agent.Payments.onTransactionStatus((reference, status) => {
    console.log(`Transaction with reference ${JSON.stringify(reference)} has status ${JSON.stringify(status)})`);
});

Transaction Result

The transaction result will have the following properites:

Name Path Description Example Value
Charges charges The charges requested {total: 4, tax: 1}
Masked PAN cardInfo.maskedPAN The masked PAN of the Card Provided {..., cardInfo: {..., maskedPAN: '541333******0011'}}
Card Holder Name cardInfo.cardHolderName The card holder name on the Card {..., cardInfo: {..., cardHolderName: 'UAT USA/TEST CARD 10'}}
Card Type Code cardInfo.cardType.code The code of the Card Type {..., cardType: {..., code: 1}}
Card Type cardInfo.cardType.type The string type of the Card {..., cardType: {..., type: 'VISA'}}
Card Expiry Month cardInfo.cardExpiry.month The Expiry Month of the Card {..., cardExpiry: {..., month: 12}}
Card Expiry Year cardInfo.cardExpiry.year The Expiry Year of the Card {..., cardExpiry: {..., year: 2022}}
Reference Invoice No cardInfo.reference.invoiceNumber The Invoice No provided {..., reference: {..., invoiceNumber: '1024'}}
Reference Invoice Date cardInfo.reference.invoiceDate The Invoice Date provided {..., reference: {..., invoiceDate: '2019-12-23T04:35:04.636Z'}}
Transaction ID transactionID The MeldCX Internsal ID of the transaction {..., transactionId: '99e4f3bb-e6f9-4ad4-9ca3-5398b0bd7b54'}
Approved approved If this transaction was approved {..., approved: true}
Gateway Request ID response.requestID The Request ID from the Gateway {..., response: {..., requestID: '01Z6HT2V0R01U67LG1LOM4POFBRGJ8OI'}}
Gateway Result Code response.resultCode The Response Code from the Gateway {..., response: {..., resultCode: 200}}
Gateway Authorization Code response.authorizationCode The Response Code from the Gateway {..., response: {..., authorizationCode: '621575'}}
Gateway Authorization Date response.authorizationDateTime The Response Code from the Gateway {..., response: {..., authorizationDateTime: '2020-01-17T05:22:35.6164684Z'}}
Receipt response.receipt The Receipt for this Transaction {..., response: {..., receipt: 'RECEIPT EXAMPLE....'}}
Gateway Specific Response response.gatewayResponse The Raw response from the Gateway {..., gatewayResponse: {...}}
Token response.token The Token value for Token Transactions {..., response: {..., token: '9680082379174111'}}

A full example response object is show below:

{
    "charges": {
        "total": 4
    },
    "cardInfo": {
        "maskedPAN": "541333******0011",
        "cardHolderName": "UAT USA/TEST CARD 10",
        "cardType": {
            "code": 1,
            "type": "Mastercard"
        },
        "cardExpiry": {
            "month": 12,
            "year": 2022
        },
        "entryMethod": {"code": 1, "type": "MSR"}
    },
    "reference": {
        "invoiceNumber": "e0f2619f-5f3c-4f83-8",
        "invoiceDate": "2019-12-23T04:35:04.636Z"
    },
    "transactionId": "99e4f3bb-e6f9-4ad4-9ca3-5398b0bd7b54",
    "approved": true,
    "response": {
        "token": "9680082379174111",
        "requestID": "01Z6HT2V0R01U67LG1LOM4POFBRGJ8OI",
        "receipt": "************* AUTHORIZATION *************\n APPROVED\n\nTotal: $4.00\n\nCard Type: MASTERCARD\nCard Entry: MAG STRIPE\nAcct #: 541333******0011\nApproval Code: 621575",
        "resultCode": 200,
        "authorizationCode": "621575",
        "authorizationDateTime": "2020-01-17T05:22:35.6164684Z"
    },
    "gatewayResponse": {}
}

Entry Methods

Entry Method Code
None 0
MSR 1
Chip 2
EMVContactless 4
Manual 8
RFID 16
Scanned 32
Loyalty 64

Errors

Exception Name Code Description
PaymentException Payment.InvalidCharge Thrown when an invalid charge value is passed to the Start Transaction function
PaymentException Payment.NotReady Thrown when the payments engine is not ready to process transaction
PaymentException Payment.NoTerminal Thrown when no terminal is present or configured
PaymentException Payment.TerminalPairingFailed Thrown when a request to pair fails
PaymentException Payment.CancelFailed Thrown when an attempt to cancel a transaction fails.
PaymentException Payment.TransactionCancelled Thrown when a transaction is cancelled
PaymentException Payment.TransactionInProgress Thrown when a transaction is in progress but you attempt to make another
PaymentGatewayException UnknownTransactionType Thrown when an unkown transaction type is provided
PaymentGatewayException Gateway.Down Thrown when the payment gateway is down
PaymentGatewayException Gateway.TransactionNotCancellable Thrown when a transaction cannot be cancelled
TransactionRejectedException {Gateway Specific Code} Thrown when a transaction is rejected/declined by the gateway
DisconnectedException Terminal.Disconnected Thrown when the payment terminal is disconnected
PaymentTerminalException Terminal.PairingInProgress Thrown when attempting to pair when a pairing process is already running
AgentTimedOutException Agent.TimedOutException Thrown when an API call times out, when an operation takes longer than expected
PaymentGatewayException Misc See Gateway Specific Section here
PaymentTerminalException Misc See Terminal Specific Section here

Common Errors

Problem Pinpad Gateway Exception Name Code Description/Reason
Bad Mag Strip Read VP6800 N/A PaymentTerminalException EMV_RESULT_CODE_MSR_CARD_ERROR_FALLBACK Bad magnetic strip read or faulty stripe
Card Expired N/A Freeway TransactionRejectedException 233 This will depend on the bank Test with 55.01
Card Swiped VP6800 TBC TBC TBC
Processing Failure N/A Freeway PaymentGatewayException 150 This will depend on the bank Test with 55.02
Debit Card Rejection VP6800 N/A TBC TBC To be Confirmed

Emulator

A Payments emulation component has been developed for the Agent Emulator, this can be found in the Payments section of the Emulator Menu.

img

Emulating Payment System State

Under the section titled System there is a drop down list from which you can set the state of the Payments System, the following states correspond to these errors being throw by the system:

State Error Code
Initialising PaymentException Payment.NotReady
Ready N/A (No Error) N/A (No Error)
GatewayOffline PaymentGatewayException Gateway.Down
TerminalOffline PaymentException Payment.NoTerminal
TerminalPairingFailed PaymentException Payment.TerminalPairingFailed
ErrorGateway PaymentException Payment.NotReady
ErrorTerminal PaymentException Payment.NotReady
ErrorConfiguration PaymentException Payment.NotReady

Emulating Gateway State

Under the section titled Gateway there are 2 drop down lists:

  • The first allows you to set the state of the Gateway API.
  • The second allows you to set the gateway action for the transactions it receives.

Gateway State and Errors:

State Error Code
Up N/A (No Error) N/A (No Error)
Down PaymentGatewayException Gateway.Down
Unknown PaymentGatewayException Gateway.Down

Gateway Result/Actions:

State Error Code
Accept N/A (No Error) N/A (No Error)
Decline TransactionRejectedException Transaction.Rejected
Error PaymentGatewayException Gateway specific error code

Emulating Terminal State

The Status column shows the emulated display of the payment terminal and the prompts that the user would see.

The Input Method column contains a drop down list that allows you to select the emulated input method for the card, this may be MSR, Chip and EMV.

The Swipe, Tap, Insert button allows you to invoke the Swipe, Tap or Insert action. This buttons action changes based on the Input Method you select.

The CV Trigger Limit designates the amount the charge to the card can be before it triggers a Card Holder Verification request, this only applies to transaction of type Tap & Insert (EMV Transactions).

Working with EMV

EMV mantains much stricter and safer controls over what transactions are supported and the conditions around verifying the cardholder before releasing the data stored on the card, if certain conditions are met the customer may be prompted to enter their PIN or to perform some other kind of verification.

We have added support to emulate this behaviour in our Emulator. When the transaction amount is greater than or equal to that specified in the CV Trigger Limit drop down list, the emulator will trigger the "CVM Required" event, you can listen to this as follows:

Agent.Payments.onCVMRequested((cvMethod: CVMethod, reference: TransactionReference) => {
    console.log(`The transaction with reference: ${reference.invoiceNumber} is requesting to perform Cardholder Verification via ${CVMMethod.type}`);

    // At this time the emulator only returns a Cardholder Verification method of type 'ONLINE_PIN'.
}));

Additionally you can emulate a successful Cardholder Verification by clicking on the CV Verify button which will temporarily replace the Insert/Tap button.

The transaction result will reflect the differing presentation methods with the result.cardInfo.entryMethod objects values differing depending on the Entry method

Terminal Errors

We have added support for emulating a wide variety of payment terminal errors:

Connectivity Errors

The Connectivity column contains a drop down that allows you to switch the connectivity state of the payment terminal.

Driver & Terminal Errors

Status Errors
Name Code Message
PaymentTerminalException STATUS_CODE_00 STATUS_CODE_00: OK
PaymentTerminalException STATUS_CODE_01 STATUS_CODE_01: Incorrect Header Tag
PaymentTerminalException STATUS_CODE_02 STATUS_CODE_02: Unknown Command
PaymentTerminalException STATUS_CODE_03 STATUS_CODE_03: Unknown Sub-command
PaymentTerminalException STATUS_CODE_04 STATUS_CODE_04: CRC Error in Frame
PaymentTerminalException STATUS_CODE_05 STATUS_CODE_05: Incorrect Parameter
PaymentTerminalException STATUS_CODE_06 STATUS_CODE_06: Parameter Not Supported
PaymentTerminalException STATUS_CODE_07 STATUS_CODE_07: Incorrect Data Format
PaymentTerminalException STATUS_CODE_08 STATUS_CODE_08: Timeout
PaymentTerminalException STATUS_CODE_0A STATUS_CODE_0A: Failed
PaymentTerminalException STATUS_CODE_0B STATUS_CODE_0B: Command not Allowed
PaymentTerminalException STATUS_CODE_0C STATUS_CODE_0C: Sub-command not Allowed
PaymentTerminalException STATUS_CODE_0D STATUS_CODE_0D: Buffer Overflow
PaymentTerminalException STATUS_CODE_0E STATUS_CODE_0E: User Interface Event
PaymentTerminalException STATUS_CODE_0F STATUS_CODE_0F: Decryption Error
PaymentTerminalException STATUS_CODE_16 STATUS_CODE_16: Busy
PaymentTerminalException STATUS_CODE_20 STATUS_CODE_20: Directory not found
PaymentTerminalException STATUS_CODE_21 STATUS_CODE_21: Length error
PaymentTerminalException STATUS_CODE_22 STATUS_CODE_22: Transaction Declined
PaymentTerminalException STATUS_CODE_23 STATUS_CODE_23: Request Online Auth
PaymentTerminalException STATUS_CODE_24 STATUS_CODE_24: OK – DesFire
PaymentTerminalException STATUS_CODE_25 STATUS_CODE_25: OK – ViVOComm
PaymentTerminalException STATUS_CODE_27 STATUS_CODE_27: File too big
PaymentTerminalException STATUS_CODE_28 STATUS_CODE_28: No space
PaymentTerminalException STATUS_CODE_30 STATUS_CODE_30: Request Online Auth
PaymentTerminalException STATUS_CODE_31 STATUS_CODE_31: Request Online PIN
PaymentTerminalException STATUS_CODE_32 STATUS_CODE_32: Request Signature
PaymentTerminalException STATUS_CODE_33 STATUS_CODE_33: Advice Required
PaymentTerminalException STATUS_CODE_34 STATUS_CODE_34: Reversal Required
PaymentTerminalException STATUS_CODE_35 STATUS_CODE_35: Advice and Reversal Required
PaymentTerminalException STATUS_CODE_36 STATUS_CODE_36: No Advice or Reversal Required
PaymentTerminalException STATUS_CODE_39 STATUS_CODE_39: Reserved
PaymentTerminalException STATUS_CODE_3A STATUS_CODE_3A: Fallback from Contact (ICC) to Magstripe
PaymentTerminalException STATUS_CODE_3B STATUS_CODE_3B: Fallback from Contactless to Contact
PaymentTerminalException STATUS_CODE_3C STATUS_CODE_3C: Fallback from Contactless to Magstripe
PaymentTerminalException STATUS_CODE_3D STATUS_CODE_3D: Fallback from Contactless to Other Interface
PaymentTerminalException STATUS_CODE_41 STATUS_CODE_41: Unknown SAM Error
PaymentTerminalException STATUS_CODE_42 STATUS_CODE_42: Invalid data detected by SAM
PaymentTerminalException STATUS_CODE_43 STATUS_CODE_43: Incomplete data detected by SAM
PaymentTerminalException STATUS_CODE_44 STATUS_CODE_44: CA Public Key Failed Hash Check
PaymentTerminalException STATUS_CODE_45 STATUS_CODE_45: Invalid key hash algorithm
PaymentTerminalException STATUS_CODE_46 STATUS_CODE_46: Invalid key encryption algorithm
PaymentTerminalException STATUS_CODE_47 STATUS_CODE_47: Invalid modulus length
PaymentTerminalException STATUS_CODE_48 STATUS_CODE_48: Invalid exponent
PaymentTerminalException STATUS_CODE_49 STATUS_CODE_49: Key already exists
PaymentTerminalException STATUS_CODE_4A STATUS_CODE_4A: No space for new RID
PaymentTerminalException STATUS_CODE_4B STATUS_CODE_4B: Key not found
PaymentTerminalException STATUS_CODE_4C STATUS_CODE_4C: Crypto not responding
PaymentTerminalException STATUS_CODE_4D STATUS_CODE_4D: Crypto communication error
PaymentTerminalException STATUS_CODE_4E STATUS_CODE_4E: Key slots full for this RID
PaymentTerminalException STATUS_CODE_4F STATUS_CODE_4F: All key slots are full
PaymentTerminalException STATUS_CODE_50 STATUS_CODE_50: Key data is bad or corrupt
PaymentTerminalException STATUS_CODE_51 STATUS_CODE_51: Keys out of sync
PaymentTerminalException STATUS_CODE_55 STATUS_CODE_55: Illegal duplicate data set
PaymentTerminalException STATUS_CODE_56 STATUS_CODE_56: Indication to fail the transaction to Pass Through Mode
PaymentTerminalException STATUS_CODE_57 STATUS_CODE_57: No payment transaction occurred. The response is loyalty only.
PaymentTerminalException STATUS_CODE_58 STATUS_CODE_58: Contactless Data Exchange
PaymentTerminalException STATUS_CODE_59 STATUS_CODE_59: Request Authentication
PaymentTerminalException STATUS_CODE_60 STATUS_CODE_60: Data not exist
PaymentTerminalException STATUS_CODE_A1 STATUS_CODE_A1: No PAN data avaiable
PaymentTerminalException STATUS_CODE_A2 STATUS_CODE_A2: MSR Error See IDTech doco
Transaction Errors
Name Code Message
PaymentTerminalException TRANSACTION_ERROR_01 TRANSACTION_ERROR_01: Out of Sequence Command
PaymentTerminalException TRANSACTION_ERROR_02 TRANSACTION_ERROR_02: Go to Contact Interface
PaymentTerminalException TRANSACTION_ERROR_03 TRANSACTION_ERROR_03: Transaction Amount is Zero
PaymentTerminalException TRANSACTION_ERROR_04 TRANSACTION_ERROR_04: Go to Other Interface
PaymentTerminalException TRANSACTION_ERROR_05 TRANSACTION_ERROR_05: Go to Nearby Contact Interface
PaymentTerminalException TRANSACTION_ERROR_06 TRANSACTION_ERROR_06: Go to Magstripe Interface
PaymentTerminalException TRANSACTION_ERROR_20 TRANSACTION_ERROR_20: RF State Error
PaymentTerminalException TRANSACTION_ERROR_21 TRANSACTION_ERROR_21: Collision Error
PaymentTerminalException TRANSACTION_ERROR_23 TRANSACTION_ERROR_23: Amount over Max Limit
PaymentTerminalException TRANSACTION_ERROR_25 TRANSACTION_ERROR_25: Card Blocked
PaymentTerminalException TRANSACTION_ERROR_26 TRANSACTION_ERROR_26: Card Expired
PaymentTerminalException TRANSACTION_ERROR_27 TRANSACTION_ERROR_27: Unsupported Card
PaymentTerminalException TRANSACTION_ERROR_30 TRANSACTION_ERROR_30: Card did not respond
PaymentTerminalException TRANSACTION_ERROR_40 TRANSACTION_ERROR_40: Unkown Data Element
PaymentTerminalException TRANSACTION_ERROR_41 TRANSACTION_ERROR_41: Required Data Element(s) Missing
PaymentTerminalException TRANSACTION_ERROR_42 TRANSACTION_ERROR_42: Card Generated AAC
PaymentTerminalException TRANSACTION_ERROR_43 TRANSACTION_ERROR_43: Card Generated ARQC
PaymentTerminalException TRANSACTION_ERROR_44 TRANSACTION_ERROR_44: SDA/DDA Failed
PaymentTerminalException TRANSACTION_ERROR_50 TRANSACTION_ERROR_50: SDA/DDA/CDDA Failed
PaymentTerminalException TRANSACTION_ERROR_51 TRANSACTION_ERROR_51: SDA/DDA/CDDA Failed
PaymentTerminalException TRANSACTION_ERROR_52 TRANSACTION_ERROR_52: SDA Failed (SSAD)
PaymentTerminalException TRANSACTION_ERROR_53 TRANSACTION_ERROR_53: DDA/CDDA Failed
PaymentTerminalException TRANSACTION_ERROR_54 TRANSACTION_ERROR_54: DDA/CDDA Failed
PaymentTerminalException TRANSACTION_ERROR_55 TRANSACTION_ERROR_55: Processing Restrictions Failed
PaymentTerminalException TRANSACTION_ERROR_56 TRANSACTION_ERROR_56: TRM Failed
PaymentTerminalException TRANSACTION_ERROR_57 TRANSACTION_ERROR_57: Cardholder Verification Failed
PaymentTerminalException TRANSACTION_ERROR_58 TRANSACTION_ERROR_58: TAA Failed
PaymentTerminalException TRANSACTION_ERROR_61 TRANSACTION_ERROR_61: SD Memory Error
PaymentTerminalException TRANSACTION_ERROR_70 TRANSACTION_ERROR_70: Contact EMV Error
PaymentTerminalException TRANSACTION_ERROR_80 TRANSACTION_ERROR_80: No Merchants
PaymentTerminalException TRANSACTION_ERROR_81 TRANSACTION_ERROR_81: Data Element Parse Error
PaymentTerminalException TRANSACTION_ERROR_82 TRANSACTION_ERROR_82: Merchant Data Error
PaymentTerminalException TRANSACTION_ERROR_83 TRANSACTION_ERROR_83: System Memory Error
PaymentTerminalException TRANSACTION_ERROR_84 TRANSACTION_ERROR_84: Application Skip Error
PaymentTerminalException TRANSACTION_ERROR_85 TRANSACTION_ERROR_85: Application Version Error
EMV Errors

The EMV Errors will be returned in the form of {CEMV_APP_ERROR_FN}.{CEMV_APP_ERROR_STATE}

Name Code
PaymentTerminalException {CEMV_APP_ERROR_FN}.{CEMV_APP_ERROR_STATE}
CEMV_APP_ERROR_FN Code
CEMV_APP_ERROR_FN_NONE
CEMV_APP_ERROR_FN_CEMV_INITIALIZE
CEMV_APP_ERROR_FN_CEMV_INITIATE_TRANSACTION
CEMV_APP_ERROR_FN_CEMV_BUILD_CANDIDATE_LIST
CEMV_APP_ERROR_FN_CEMV_FINAL_APPLICATION_SELECTION
CEMV_APP_ERROR_FN_CEMV_INITIATE_APPLICATION
CEMV_APP_ERROR_FN_CEMV_READ_APPLICATION_DATA
CEMV_APP_ERROR_FN_CEMV_OFFLINE_DATA_AUTHENTICATION
CEMV_APP_ERROR_FN_CEMV_PROCESS_RESTRICTIONS
CEMV_APP_ERROR_FN_CEMV_CARDHOLDER_VERIFICATION
CEMV_APP_ERROR_FN_CEMV_CARDHOLDER_VERIFICATION_CONTINUE
CEMV_APP_ERROR_FN_CEMV_TERMINAL_RISK_MANAGEMENT
CEMV_APP_ERROR_FN_CEMV_TERMINAL_ACTION_ANALYSIS
CEMV_APP_ERROR_FN_CEMV_CARD_ACTION_ANALYSIS
CEMV_APP_ERROR_FN_CEMV_COMPLETION
CEMV_APP_ERROR_FN_CEMV_TRANSACTION_MODE
CEMV_APP_ERROR_FN_CEMV_GET_APPLICATION_NAME
CEMV_APP_ERROR_FN_CEMV_SET_DATA_ELEMENTS
CEMV_APP_ERROR_FN_CEMV_GET_DATA_ELEMENTS
CEMV_APP_ERROR_FN_CEMV_UPDATE_EMV_KERNEL_CONFIG_FILE
CEMV_APP_ERROR_FN_UI_DISPLAY_CLEAR
CEMV_APP_ERROR_FN_UI_DISLAY_TEXT
CEMV_APP_ERROR_FN_UI_DISPLAY_BUTTON
CEMV_APP_ERROR_FN_UI_LIST_CREATE
CEMV_APP_ERROR_FN_UI_LIST_ADD_ITEM
CEMV_APP_ERROR_FN_UI_LIST_READ_BUTTON
CEMV_APP_ERROR_FN_UI_LIST_GET_SELECTED_ITEM
CEMV_APP_ERROR_FN_PCI_START_CUSTOM_DISPLAY_MODE
CEMV_APP_ERROR_STATE Code
CEMV_APP_ERROR_STATE_NONE
CEMV_APP_ERROR_STATE_SERIAL_COMM
CEMV_APP_ERROR_STATE_VALIDATE_COMMAND
CEMV_APP_ERROR_STATE_TRANSACTION
CEMV_APP_ERROR_STATE_CANDIDATE_SELECTION
CEMV_APP_ERROR_STATE_DISPLAY_APP_MENU
CEMV_APP_ERROR_STATE_LOAD_CONFIG_GROUP
CEMV_APP_ERROR_STATE_CARD_REMOVAL
CEMV_APP_ERROR_STATE_UNKNOWN