There are 3 loyalty card features available for IDTech VP3300.
Use the CoreLoyaltyConfig
builder to configure the Apple VAS settings before initializing the device.
Required fields:
HashMap data = new HashMap();
data.put("loyaltyConfig", new CoreLoyaltyConfig.Builder()
.addAppleVasMerchant("pass.com.pronto.id-tech.demo", "www.idtechproducts.com")
.setAppleVasPrivateKey( "F5368708933920553B7B9FFB16AEED9C77D5BFD9662AF149A6B9F965B73F0CCA")
.build());
JavaTerminal.getInstance().initDevice(DeviceEnum.IDTECH, DeviceConnectionType.USB, data);
HashMap data = new HashMap();
data.put("loyaltyConfig", new CoreLoyaltyConfig.Builder()
.addAppleVasMerchant("pass.com.pronto.id-tech.demo", "www.idtechproducts.com")
.setAppleVasPrivateKey( "F5368708933920553B7B9FFB16AEED9C77D5BFD9662AF149A6B9F965B73F0CCA")
.build());
AndroidTerminal.getInstance().initDevice(DeviceEnum.IDTECH, DeviceConnectionType.USB, data);
Dictionary data = new Dictionary();
data.Add("loyaltyConfig", new CoreLoyaltyConfig.Builder()
.AddAppleVasMerchant("pass.com.pronto.id-tech.demo", "www.idtechproducts.com")
.SetAppleVasPrivateKey("F5368708933920553B7B9FFB16AEED9C77D5BFD9662AF149A6B9F965B73F0CCA")
.Build());
Terminal.Instance.InitDevice(DeviceEnum.IDTECH, DeviceConnectionType.USB, data);
{
"type": "REQ_INIT_DEVICE",
"data": {
"device": "IDTECH",
"connectionType": "USB",
"loyaltyConfig": {
"appleVasPrivateKey": "F5368708933920553B7B9FFB16AEED9C77D5BFD9662AF149A6B9F965B73F0CCA",
"appleVasMerchants": [
{
"merchantId": "pass.com.pronto.id-tech.demo",
"merchantUrl": "www.idtechproducts.com"
}
]
}
}
}
Use the CoreLoyaltyConfig
builder to configure the Google Smart TAP settings before initializing the device.
Required fields:
HashMap data = new HashMap();
data.put("loyaltyConfig", new CoreLoyaltyConfig.Builder()
.setGoogleSmartTapCollectorId(87133300)
.setGoogleSmartTapPrivateKeyVersion(10)
.setGoogleSmartTapPrivateKey( "F5368708933920553B7B9FFB16AEED9C77D5BFD9662AF149A6B9F965B73F0CCA")
.build());
JavaTerminal.getInstance().initDevice(DeviceEnum.IDTECH, DeviceConnectionType.USB, data);
HashMap data = new HashMap();
data.put("loyaltyConfig", new CoreLoyaltyConfig.Builder()
.setGoogleSmartTapCollectorId(87133300)
.setGoogleSmartTapPrivateKeyVersion(10)
.setGoogleSmartTapPrivateKey( "F5368708933920553B7B9FFB16AEED9C77D5BFD9662AF149A6B9F965B73F0CCA")
.build());
AndroidTerminal.getInstance().initDevice(DeviceEnum.IDTECH, DeviceConnectionType.USB, data);
Dictionary data = new Dictionary();
data.Add("loyaltyConfig", new CoreLoyaltyConfig.Builder()
.SetGoogleSmartTapCollectorId(87133300)
.SetGoogleSmartTapPrivateKeyVersion(10)
.SetGoogleSmartTapPrivateKey("F5368708933920553B7B9FFB16AEED9C77D5BFD9662AF149A6B9F965B73F0CCA")
.Build());
Terminal.Instance.InitDevice(DeviceEnum.IDTECH, DeviceConnectionType.USB, data);
{
"type": "REQ_INIT_DEVICE",
"data": {
"device": "IDTECH",
"connectionType": "USB",
"loyaltyConfig": {
"googleSmartTapCollectorId": 87133300,
"googleSmartTapPrivateKeyVersion": 10,
"googleSmartTapPrivateKey": "F5368708933920553B7B9FFB16AEED9C77D5BFD9662AF149A6B9F965B73F0CCA"
}
}
}
We only support MIFARE Classic and MIFARE Ultralight cards.
Before using the MIFARE cards the merchant must write their own data to the MIFARE card. This can be done using IDTech uDemo.
The example below will show how to write a simple "Hello world!" using uDemo:
Card information can be read using the Android app NFC TagInfo by NXP.
Use the CoreLoyaltyConfig
builder to configure the MIFARE settings before initializing the device.
Required field:
Optional field:
You could specify a global or multiple sector key configurations based on your MIFARE Classic card settings.
FFFFFFFFFFFF
, there's no need to declare any authentication configurations.
When setting up a global MIFARE Classic key, the assumption is that all of the sectors use the same key
or at least the blocks requested belong to the sectors protected by the key. Use the method setMiFareClassicAuthGlobalKeyConfig
to configure it.
In case you have sectors with different keys, use the method addMiFareClassicAuthSectorKeyConfig
to add a sector key configuration.
HashMap data = new HashMap();
data.put("loyaltyConfig", new CoreLoyaltyConfig.Builder()
.setMiFareBlocksToRead(new byte[] { 1, 2, 3 })
.setMiFareClassicAuthGlobalKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF") // replace key
.addMiFareClassicAuthSectorKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF", new short[] { 0, 1 }) // replace key
.addMiFareClassicAuthSectorKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF", new short[] { 2, 3 }) // replace key
.build());
JavaTerminal.getInstance().initDevice(DeviceEnum.IDTECH, DeviceConnectionType.USB, data);
HashMap data = new HashMap();
data.put("loyaltyConfig", new CoreLoyaltyConfig.Builder()
.setMiFareBlocksToRead(new byte[] { 1, 2, 3 })
.setMiFareClassicAuthGlobalKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF") // replace key
.addMiFareClassicAuthSectorKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF", new short[] { 0, 1 }) // replace key
.addMiFareClassicAuthSectorKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF", new short[] { 2, 3 }) // replace key
.build());
AndroidTerminal.getInstance().initDevice(DeviceEnum.IDTECH, DeviceConnectionType.USB, data);
Dictionary data = new Dictionary();
data.Add("loyaltyConfig", new CoreLoyaltyConfig.Builder()
.SetMiFareBlocksToRead(new byte[] { 1, 2, 3 })
.SetMiFareClassicAuthGlobalKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF") // replace key
.AddMiFareClassicAuthSectorKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF", new short[] { 0, 1 }) // replace key
.AddMiFareClassicAuthSectorKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF", new short[] { 2, 3 }) // replace key
.Build());
Terminal.Instance.InitDevice(DeviceEnum.IDTECH, DeviceConnectionType.USB, data);
{
"type": "REQ_INIT_DEVICE",
"data": {
"device": "IDTECH",
"connectionType": "USB",
"loyaltyConfig": {
"miFareBlocksToRead": [ 1, 2, 3 ],
"miFareClassicAuthConfig": {
"globalKeyMode": "KEY_A",
"globalKeyValue": "FFFFFFFFFFFF",
"sectorKeyConfigs": [
{
"keyMode": "KEY_A",
"keyValue": "FFFFFFFFFFFF",
"sectors": [ 0, 1 ]
},
{
"keyMode": "KEY_A",
"keyValue": "FFFFFFFFFFFF",
"sectors": [ 2, 3 ]
}
]
}
}
}
}
After the device is initialized with the correct configuration you can set the parameter Loyalty Mode in a CoreSale
to process a Loyalty and/or Payment Card.
CoreLoyaltyMode.LOYALTY_ONLY
.
CoreSale sale = new CoreSale();
sale.setAmount(BigDecimal.valueOf(1.00));
sale.setLoyaltyMode(CoreLoyaltyMode.LOYALTY_AND_PAYMENT);
JavaTerminal.getInstance().processSale(sale);
CoreSale sale = new CoreSale();
sale.setAmount(BigDecimal.valueOf(1.00));
sale.setLoyaltyMode(CoreLoyaltyMode.LOYALTY_AND_PAYMENT);
AndroidTerminal.getInstance().processSale(sale);
CoreSale sale = new CoreSale();
sale.amount = 1.00m;
sale.loyaltyMode = CoreLoyaltyMode.LOYALTY_AND_PAYMENT;
Terminal.Instance.ProcessSale(saleDevice);
{
"type": "REQ_PROCESS_SALE",
"data": {
"amount": 1.5,
"loyaltyMode": "LOYALTY_ONLY"
}
}
It is possible to change the Google Smart TAP Collector ID on a per transaction basis. This can be done on the CoreSale
object using the method setGoogleSmartTapCollectorId
:
CoreSale sale = new CoreSale();
sale.setAmount(BigDecimal.valueOf(1.00));
sale.setGoogleSmartTapCollectorId(87133300);
sale.setLoyaltyMode(CoreLoyaltyMode.LOYALTY_AND_PAYMENT);
JavaTerminal.getInstance().processSale(sale);
CoreSale sale = new CoreSale();
sale.setAmount(BigDecimal.valueOf(1.00));
sale.setGoogleSmartTapCollectorId(87133300);
sale.setLoyaltyMode(CoreLoyaltyMode.LOYALTY_AND_PAYMENT);
AndroidTerminal.getInstance().processSale(sale);
CoreSale sale = new CoreSale();
sale.amount = 1.00m;
sale.googleSmartTapCollectorId = 87133300;
sale.loyaltyMode = CoreLoyaltyMode.LOYALTY_AND_PAYMENT;
Terminal.Instance.ProcessSale(saleDevice);
{
"type": "REQ_PROCESS_SALE",
"data": {
"amount": 1.5,
"loyaltyMode": "LOYALTY_ONLY",
"googleSmartTapCollectorId": 12345678
}
}
It is possible to change the MIFARE blocks to read on a per transaction basis. This can be done on the CoreSale
object using the method setMIFAREBlocksToRead
:
CoreSale sale = new CoreSale();
sale.setAmount(BigDecimal.valueOf(1.00));
sale.setMiFareBlocksToRead(new byte[] { 1, 2 });
sale.setLoyaltyMode(CoreLoyaltyMode.LOYALTY_ONLY);
JavaTerminal.getInstance().processSale(sale);
CoreSale sale = new CoreSale();
sale.setAmount(BigDecimal.valueOf(1.00));
sale.setMiFareBlocksToRead(new byte[] { 1, 2 });
sale.setLoyaltyMode(CoreLoyaltyMode.LOYALTY_AND_PAYMENT);
AndroidTerminal.getInstance().processSale(sale);
CoreSale sale = new CoreSale();
sale.amount = 1.00m;
sale.miFareBlocksToRead = new byte[] { 1, 2 };
sale.loyaltyMode = CoreLoyaltyMode.LOYALTY_AND_PAYMENT;
Terminal.Instance.ProcessSale(saleDevice);
{
"type": "REQ_PROCESS_SALE",
"data": {
"amount": 1.5,
"loyaltyMode": "LOYALTY_ONLY",
"miFareBlocksToRead": [ 1, 2 ]
}
}
It is possible to change the MIFARE Classic authentication configuration per sale. Use the methods setMiFareClassicAuthGlobalKeyConfig
and addMiFareClassicAuthSectorKeyConfig
:
CoreSale sale = new CoreSale();
sale.setAmount(BigDecimal.valueOf(1.00));
sale.setMiFareBlocksToRead(new byte[] { 1, 2 });
sale.setMiFareClassicAuthGlobalKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF"); // replace key
sale.addMiFareClassicAuthSectorKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF", new short[] { 0, 1 }); // replace key
sale.addMiFareClassicAuthSectorKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF", new short[] { 2, 3 }); // replace key
sale.setLoyaltyMode(CoreLoyaltyMode.LOYALTY_ONLY);
JavaTerminal.getInstance().processSale(sale);
CoreSale sale = new CoreSale();
sale.setAmount(BigDecimal.valueOf(1.00));
sale.setMiFareBlocksToRead(new byte[] { 1, 2 });
sale.setMiFareClassicAuthGlobalKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF"); // replace key
sale.addMiFareClassicAuthSectorKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF", new short[] { 0, 1 }); // replace key
sale.addMiFareClassicAuthSectorKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF", new short[] { 2, 3 }); // replace key
sale.setLoyaltyMode(CoreLoyaltyMode.LOYALTY_AND_PAYMENT);
AndroidTerminal.getInstance().processSale(sale);
CoreSale sale = new CoreSale();
sale.amount = 1.00m;
sale.miFareBlocksToRead = new byte[] { 1, 2 };
sale.SetMiFareClassicAuthGlobalKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF"); // replace key
sale.AddMiFareClassicAuthSectorKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF", new short[] { 0, 1 }); // replace key
sale.AddMiFareClassicAuthSectorKeyConfig(CoreMiFareClassicAuthConfig.CoreMiFareClassicKeyMode.KEY_A, "FFFFFFFFFFFF", new short[] { 2, 3 }); // replace key
sale.loyaltyMode = CoreLoyaltyMode.LOYALTY_AND_PAYMENT;
Terminal.Instance.ProcessSale(saleDevice);
{
"type": "REQ_PROCESS_SALE",
"data": {
"amount": 1.5,
"loyaltyMode": "LOYALTY_ONLY",
"miFareBlocksToRead": [ 1, 2 ],
"miFareClassicAuthConfig": {
"globalKeyMode": "KEY_A",
"globalKeyValue": "FFFFFFFFFFFF",
"sectorKeyConfigs": [
{
"keyMode": "KEY_A",
"keyValue": "FFFFFFFFFFFF",
"sectors": [ 0 , 1 ]
},
{
"keyMode": "KEY_A",
"keyValue": "FFFFFFFFFFFF",
"sectors": [ 2, 3 ]
}
]
}
}
}
MIFARE Ultralight
cards differ from the Classic one. Compared to the Classic which has a block size of 16 bytes, Ultralight uses pages which are 4 bytes each. When reading Ultralight cards, 16 bytes of data are returned from the specified start block (page number). For example, passing block 1 would read pages 1 to 4.
Additionally, the final 4 pages of Ultralight cards are for the authentication key and are not readable. If ever the 16 bytes would include bytes from the final 4 pages, it would just read the remaining bytes starting from page 0.
When a loyalty card is read the callback onLoyaltyCardDataRetrieved
will be called with the loyalty card information in the CoreLoyaltyCardData
object. If using web sockets, a message with type RES_ON_LOYALTY_CARD_DATA_RETRIEVED
will be sent.
Required fields:
Apple VAS:
{
"type": "APPLE_VAS",
"data": "337C7A53556879496972476D6376454A73507C38383838383838387C47696E676572"
}
Google Smart TAP:
{
"type": "GOOGLE_SMARTTAP",
"data": "940349617376940106690402717979715403396375739403116369640400000000000000000000000000000000190103035463706c00656e5403116375740448d6d68c9e75c38f3f116aca37139138540347617376940106690401000000005402386c799403096f696404bdf468a1a4f2f09f59012301546e00337c7a53556879496972476d6376454a73507c38383838383838387c47696e676572"
}
The Smart Tap data is an NDEF record which you could parse on this Parser.
MIFARE:
{
"type": "MIFARE_ULTRALIGHT",
"data": "{
\"errorCode\": \"E0\",
\"cardType\": \"04\",
\"uid\": \"0455E299102880\",
\"blockData\": {
\"3\": \"00000000020000100006011011FF0000\",
\"4\": \"020000100006011011FF000000000000\",
\"5\": \"0006011011FF00000000000000000000\",
\"6\": \"11FF0000000000000000000000000000\"
}
}"
}